{"record":{"id":"b687f5568a084a76","repo":"hibernate/hibernate-orm","slug":"schema-validation-missing-table-s","errorCode":null,"errorMessage":"Schema validation: missing table [%s]","messagePattern":"Schema validation: missing table \\[(.+?)\\]","errorType":"exception","errorClass":"SchemaManagementException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java","lineNumber":127,"sourceCode":"\t\t\t}\n\t\t}\n\t}\n\n\tprotected abstract void validateTables(\n\t\t\tMetadata metadata,\n\t\t\tDatabaseInformation databaseInformation,\n\t\t\tExecutionOptions options,\n\t\t\tContributableMatcher contributableInclusionFilter,\n\t\t\tDialect dialect, Namespace namespace);\n\n\tprotected void validateTable(\n\t\t\tTable table,\n\t\t\tTableInformation tableInformation,\n\t\t\tMetadata metadata,\n\t\t\tExecutionOptions options,\n\t\t\tDialect dialect) {\n\t\tif ( tableInformation == null ) {\n\t\t\tthrow new SchemaManagementException(\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\"Schema validation: missing table [%s]\",\n\t\t\t\t\t\t\ttable.getQualifiedTableName().toString()\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tfor ( var column : table.getColumns() ) {\n\t\t\tfinal var existingColumn =\n\t\t\t\t\t//QUESTION: should this use metadata.getDatabase().toIdentifier( column.getQuotedName() )\n\t\t\t\t\ttableInformation.getColumn( toIdentifier( column.getQuotedName() ) );\n\t\t\tif ( existingColumn == null ) {\n\t\t\t\tthrow new SchemaManagementException(\n\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\t\"Schema validation: missing column [%s] in table [%s]\",\n\t\t\t\t\t\t\t\tcolumn.getName(),\n\t\t\t\t\t\t\t\ttable.getQualifiedTableName()\n\t\t\t\t\t\t)","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java#L109-L145","documentation":"Schema validation (hibernate.hbm2ddl.auto=validate, or SchemaValidator) compared each mapped entity table against live JDBC metadata and found no table under the entity's qualified name (tableInformation == null in validateTable). Validation is read-only and never creates anything, so any mapped table missing from the database aborts SessionFactory bootstrap with this error.","triggerScenarios":"SessionFactory startup with hbm2ddl.auto=validate when the extractor cannot find table.getQualifiedTableName(): the schema was never created or migrations were not run in that environment; the JDBC URL/default_schema resolves a different namespace; the physical naming strategy or @Table name produces a name that differs from the physical table (case folding on PostgreSQL, quoted vs unquoted identifiers).","commonSituations":"Deploying with ddl-auto=validate before Flyway/Liquibase has run; pointing at the wrong database/schema in the connection URL; changing the PhysicalNamingStrategy between releases; validating against a replica or role that cannot see the app schema; Postgres lowercasing unquoted CamelCase names at creation time while the mapping now expects CamelCase.","solutions":["Run the schema migrations (or SchemaExport create) in that environment before startup with validate.","Verify the connection URL, catalog, and hibernate.default_schema/default_catalog resolve the schema that actually holds the table.","Align the mapped name with the physical table: fix @Table(name=...) or use a consistent PhysicalNamingStrategy.","If the table is intentionally absent (e.g. optional module), exclude the entities from the validated metadata or drop validate for that profile."],"exampleFix":"// before: entity expects ORDERS but PostgreSQL created orders (unquoted names are folded)\n@Entity\n@Table(name = \"ORDERS\")\npublic class Order { ... }\n\n// after: match the physical name\n@Entity\n@Table(name = \"orders\")\npublic class Order { ... }","handlingStrategy":"validation","validationCode":"// Before booting with hbm2ddl.auto=validate, verify every mapped table exists via JDBC metadata\ntry (Connection c = dataSource.getConnection()) {\n    for (String table : List.of(\"orders\", \"customers\", \"order_lines\")) {\n        try (ResultSet rs = c.getMetaData().getTables(null, null, table, new String[]{\"TABLE\"})) {\n            if (!rs.next()) {\n                throw new IllegalStateException(\"Migrations incomplete: table \" + table + \" missing - refusing to validate\");\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    sessionFactory = metadata.buildSessionFactory(); // with hbm2ddl.auto=validate\n} catch (SchemaManagementException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"missing table\")) {\n        // mapping/database drift: report the qualified name, run migrations or fix naming, then retry bootstrap once\n    }\n    throw e;\n}","preventionTips":["Always run migrations before validate; wire Flyway/Liquibase to execute before Hibernate initializes","Pin hibernate.default_schema/default_catalog explicitly instead of relying on connection defaults","Run a CI step that boots the app with validate against a freshly migrated schema","Never change the PhysicalNamingStrategy without regenerating/reviewing schema names"],"tags":["hibernate","schema-validation","hbm2ddl","missing-table","entity-mapping"],"backgroundTag":"schema-validation-failed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}