hibernate/hibernate-orm · error · SchemaManagementException

SQL strings added more than once for:

Error message

SQL strings added more than once for: 

What it means

The truncate path (SchemaManagementTool.getSchemaTruncator(...).doTruncate) enforces the same one-SQL-per-exportable invariant as create and drop: each Exportable's identifier may be processed only once. A second registration of the same table/sequence/UDT aborts truncation with this SchemaManagementException naming the duplicated object.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaTruncatorImpl.java:232

						);
					}
					else if ( !dialect.canBatchTruncate() ) {
						applySqlStrings(
								dialect.getForeignKeyExporter().getSqlCreateStrings( foreignKey, metadata, context ),
								formatter,
								options,
								targets
						);
					}
				}
			}
		}
	}

	private static void checkExportIdentifier(Exportable exportable, Set<String> exportIdentifiers) {
		final String exportIdentifier = exportable.getExportIdentifier();
		if ( exportIdentifiers.contains( exportIdentifier ) ) {
			throw new SchemaManagementException( "SQL strings added more than once for: " + exportIdentifier );
		}
		exportIdentifiers.add( exportIdentifier );
	}

	@Override
	ClassLoaderService getClassLoaderService() {
		return tool.getServiceRegistry().getService( ClassLoaderService.class );
	}

}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Grep mappings for the identifier in the message and remove the duplicate registration so the object is mapped once.
  2. Rename intentional same-name objects (view vs table) so export identifiers differ.
  3. Audit MetadataSources/persistence.xml for the same class or resource added twice before building the Metadata used for truncation.

Example fix

// before
@Entity @Table(name = "cart_items")
public class CartItem { ... }
@Entity @Table(name = "cart_items")
public class LegacyCartItem { ... }

// after
@Entity @Table(name = "cart_items")
public class CartItem { ... }
// second mapping deleted; reads of legacy rows go through a native query
Defensive patterns

Strategy: validation

Validate before calling

Set<String> seen = new HashSet<>();
for (Class<?> entity : mappedEntities) {
    Table t = entity.getAnnotation(Table.class);
    String name = (t != null && !t.name().isEmpty()) ? t.name() : entity.getSimpleName();
    if (!seen.add(name.toLowerCase(Locale.ROOT))) {
        throw new IllegalStateException("Duplicate table mapping detected: " + name);
    }
}

Try / catch

try {
    schemaManagementTool.getSchemaTruncator(settings).doTruncate(metadata, options, targetDescriptor);
} catch (SchemaManagementException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("SQL strings added more than once for:")) {
        String exportable = e.getMessage().substring(e.getMessage().lastIndexOf(' ') + 1);
        // remove the duplicate mapping for `exportable`, then truncate again
    } else { throw e; }
}

Prevention

When it happens

Trigger: Truncating schema (JPA schema-generation truncate action or the SchemaTruncator API) over Metadata that maps the same exportable twice: duplicate entity table names, a class registered both annotated and via XML, duplicated auxiliary database objects, or overlapping MetadataSources merged programmatically.

Common situations: Test fixtures that truncate between test classes and hit a refactoring artifact where two entities share a table name; module merges that map the same table from two jars; auxiliary objects defined redundantly in annotations and XML.

Related errors


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