hibernate/hibernate-orm · error · SchemaManagementException

Schema validation: missing table [%s]

Error message

Schema validation: missing table [%s]

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java:127

			}
		}
	}

	protected abstract void validateTables(
			Metadata metadata,
			DatabaseInformation databaseInformation,
			ExecutionOptions options,
			ContributableMatcher contributableInclusionFilter,
			Dialect dialect, Namespace namespace);

	protected void validateTable(
			Table table,
			TableInformation tableInformation,
			Metadata metadata,
			ExecutionOptions options,
			Dialect dialect) {
		if ( tableInformation == null ) {
			throw new SchemaManagementException(
					String.format(
							"Schema validation: missing table [%s]",
							table.getQualifiedTableName().toString()
					)
			);
		}

		for ( var column : table.getColumns() ) {
			final var existingColumn =
					//QUESTION: should this use metadata.getDatabase().toIdentifier( column.getQuotedName() )
					tableInformation.getColumn( toIdentifier( column.getQuotedName() ) );
			if ( existingColumn == null ) {
				throw new SchemaManagementException(
						String.format(
								"Schema validation: missing column [%s] in table [%s]",
								column.getName(),
								table.getQualifiedTableName()
						)

View on GitHub (pinned to fad1729dce)

Solutions

  1. Run the schema migrations (or SchemaExport create) in that environment before startup with validate.
  2. Verify the connection URL, catalog, and hibernate.default_schema/default_catalog resolve the schema that actually holds the table.
  3. Align the mapped name with the physical table: fix @Table(name=...) or use a consistent PhysicalNamingStrategy.
  4. If the table is intentionally absent (e.g. optional module), exclude the entities from the validated metadata or drop validate for that profile.

Example fix

// before: entity expects ORDERS but PostgreSQL created orders (unquoted names are folded)
@Entity
@Table(name = "ORDERS")
public class Order { ... }

// after: match the physical name
@Entity
@Table(name = "orders")
public class Order { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Before booting with hbm2ddl.auto=validate, verify every mapped table exists via JDBC metadata
try (Connection c = dataSource.getConnection()) {
    for (String table : List.of("orders", "customers", "order_lines")) {
        try (ResultSet rs = c.getMetaData().getTables(null, null, table, new String[]{"TABLE"})) {
            if (!rs.next()) {
                throw new IllegalStateException("Migrations incomplete: table " + table + " missing - refusing to validate");
            }
        }
    }
}

Try / catch

try {
    sessionFactory = metadata.buildSessionFactory(); // with hbm2ddl.auto=validate
} catch (SchemaManagementException e) {
    if (e.getMessage() != null && e.getMessage().contains("missing table")) {
        // mapping/database drift: report the qualified name, run migrations or fix naming, then retry bootstrap once
    }
    throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/b687f5568a084a76. Report an issue: GitHub.