When you attempt to create a schema with an inconsistent or invalid definition, PostgreSQL raises ERROR: invalid schema definition with SQLSTATE 42P15 and condition name invalid_schema_definition. This error signals that the CREATE SCHEMA statement itself is structurally invalid, not that a sub-command within it failed due to permissions or naming conflicts.
What This Error Means
SQLSTATE 42P15 belongs to error class 42 — "Syntax Error or Access Rule Violation". This class covers errors that occur during the parsing and semantic analysis of SQL commands, before execution begins. The P in the SQLSTATE subclass indicates a PostgreSQL-specific extension to the SQL standard.
invalid_schema_definition is raised specifically during the processing of a CREATE SCHEMA statement. PostgreSQL's CREATE SCHEMA syntax allows you to optionally embed sub-commands — such as CREATE TABLE, CREATE VIEW, or GRANT — directly inside the schema definition block. If the schema name specified in a sub-command does not match the schema being created, or if the statement contains elements that are not permitted inside a CREATE SCHEMA block, PostgreSQL raises 42P15.
The error occurs at parse/analysis time and does not leave a partial schema behind. The entire CREATE SCHEMA statement is rolled back as an atomic unit, so there is no schema partially created when you encounter this error.
Common Causes
Schema name mismatch in embedded sub-commands. When embedding
CREATE TABLEor other DDL insideCREATE SCHEMA, the schema-qualified name in the sub-command must match the schema being created. Specifying a different schema name (or usingpublic.when creating a schema namedmyschema) triggers 42P15.Using a
CREATE SCHEMA ... ASform incorrectly. Older SQL standards defined aCREATE SCHEMA AUTHORIZATIONsyntax that required specific structural rules. Malformed use of theAUTHORIZATIONclause combined with explicit sub-commands can produce this error.Including DDL statements that are not allowed inside
CREATE SCHEMA. Only certain statements are valid inside aCREATE SCHEMAblock:CREATE TABLE,CREATE VIEW,CREATE INDEX,CREATE SEQUENCE,CREATE TRIGGER, andGRANT. Attempting to includeCREATE FUNCTION,CREATE TYPE,ALTER TABLE, or other unsupported DDL inside the block raises this error.
How to Fix invalid_schema_definition
Remove the schema qualifier from embedded sub-commands, or match it exactly. Statements inside a
CREATE SCHEMAblock are implicitly scoped to the new schema; you do not need to qualify object names, and if you do, the qualifier must match.-- WRONG: schema qualifier mismatch CREATE SCHEMA myschema CREATE TABLE public.mytable (id int); -- CORRECT: no qualifier needed inside the block CREATE SCHEMA myschema CREATE TABLE mytable (id int); -- CORRECT: qualifier matches the schema being created CREATE SCHEMA myschema CREATE TABLE myschema.mytable (id int);Move unsupported DDL outside the
CREATE SCHEMAblock. If you need to create functions, types, or runALTERstatements, do so after theCREATE SCHEMAstatement completes.-- WRONG: CREATE FUNCTION is not allowed inside CREATE SCHEMA CREATE SCHEMA myschema CREATE TABLE mytable (id int) CREATE FUNCTION myfunc() RETURNS void AS $$ $$ LANGUAGE sql; -- CORRECT: separate the statements CREATE SCHEMA myschema CREATE TABLE mytable (id int); CREATE FUNCTION myschema.myfunc() RETURNS void AS $$ $$ LANGUAGE sql;Use the
AUTHORIZATIONclause correctly. If you want to create a schema owned by a specific role, use theAUTHORIZATIONclause on theCREATE SCHEMAline itself, not inside sub-commands.-- Create schema owned by a specific role CREATE SCHEMA myschema AUTHORIZATION myrole CREATE TABLE mytable (id int);Split complex schema setups into individual statements. For any non-trivial schema setup, prefer running
CREATE SCHEMAfirst (without embedded sub-commands), then running each DDL statement independently. This is more readable, easier to debug, and avoids the restrictions on what is permitted inside the block.BEGIN; CREATE SCHEMA myschema; CREATE TABLE myschema.orders (id bigint PRIMARY KEY, created_at timestamptz NOT NULL); CREATE VIEW myschema.recent_orders AS SELECT * FROM myschema.orders WHERE created_at > now() - interval '7 days'; GRANT USAGE ON SCHEMA myschema TO app_user; GRANT SELECT ON ALL TABLES IN SCHEMA myschema TO app_user; COMMIT;
Additional Information
- SQLSTATE 42P15 is a PostgreSQL-specific error code not found in the SQL standard. It is not commonly encountered in day-to-day development because inline
CREATE SCHEMAsub-commands are a rarely used feature; most developers create schemas withCREATE SCHEMA name;and then issue separate DDL statements. - Related error codes in class 42 include
42601(syntax_error),42P01(undefined_table),42P02(undefined_parameter), and42P07(duplicate_table). - Most PostgreSQL client drivers (psycopg2, psycopg3, asyncpg, JDBC) expose this as a
ProgrammingErrororSQLSyntaxErrorExceptionwith the SQLSTATE code available on the exception object. - ORMs and migration tools (Alembic, Flyway, Liquibase) rarely use inline
CREATE SCHEMAsub-commands; they issue separate DDL statements, so 42P15 is unlikely to appear in ORM-generated migrations. If you see it in a migration, the migration script was likely hand-written with incorrect syntax. - This error has been present since at least PostgreSQL 8.x and the behavior has not changed across major versions.
Frequently Asked Questions
Does this error mean my schema was partially created?
No. CREATE SCHEMA is transactional in PostgreSQL. If the statement raises 42P15, no schema is created and no sub-commands are executed. The database state is unchanged.
Can I use CREATE SCHEMA with embedded sub-commands in a transaction block?
Yes. The CREATE SCHEMA statement itself is transactional. However, the error occurs during parse/analysis before execution, so wrapping the statement in BEGIN/COMMIT does not prevent or change the error — it just means the rollback is automatic regardless.
Why does PostgreSQL even support inline sub-commands in CREATE SCHEMA?
The syntax originates from the SQL standard, which defined CREATE SCHEMA as a way to atomically create a schema and its initial objects in one statement. In practice, almost no PostgreSQL code in the wild uses this form. The standalone CREATE SCHEMA name; approach followed by separate DDL is far more common and avoids the schema-name matching restriction entirely.
What is the difference between 42P15 and a permissions error when creating a schema?
42P15 indicates a structural problem with the CREATE SCHEMA statement itself. Permission errors (e.g., not having CREATE privilege on the database) produce SQLSTATE 42501 (insufficient_privilege) instead. If you can create a bare CREATE SCHEMA name; without error, the issue is with the contents of your schema definition block, not with your privileges.