hibernate/hibernate-orm · error · UnknownParameterException
Unable to locate parameter `%s.%s` for %s - %s : %s
Error message
Unable to locate parameter `%s.%s` for %s - %s : %s
What it means
JdbcValueBindingsImpl.bindValue resolves a JdbcValueDescriptor for (tableName, columnName, usage) from the mutation's parameter descriptors; when none matches it throws UnknownParameterException formatted as 'Unable to locate parameter `table.column` for usage - MUTATIONTYPE : rolePath'. It means a value is being bound for a column that does not exist in the generated INSERT/UPDATE/DELETE parameter list for that table.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/engine/jdbc/mutation/internal/JdbcValueBindingsImpl.java:64
@Override
public BindingGroup getBindingGroup(String tableName) {
final String normalizedTableName = ( tableName );
return bindingGroupMap.get( normalizedTableName );
}
@Override
public void bindValue(
Object value,
String tableName,
String columnName,
ParameterUsage usage) {
// Normalize column name BEFORE calling resolveValueDescriptor because
// AbstractJdbcMutation.findValueDescriptor expects normalized names
final var jdbcValueDescriptor =
jdbcValueDescriptorAccess.resolveValueDescriptor( tableName, columnName, usage );
if ( jdbcValueDescriptor == null ) {
throw new UnknownParameterException( mutationType, mutationTarget, tableName, columnName, usage );
}
// Normalize table name for storage to match cycle-breaking lookups
final String physicalTableName = jdbcValueDescriptorAccess.resolvePhysicalTableName( tableName );
resolveBindingGroup( ( physicalTableName ) )
.bindValue( columnName, value, jdbcValueDescriptor );
}
private BindingGroup resolveBindingGroup(String tableName) {
final var existing = bindingGroupMap.get( tableName );
if ( existing != null ) {
assert tableName.equals( existing.getTableName() );
return existing;
}
else {
final var created = new BindingGroup( tableName );
bindingGroupMap.put( tableName, created );
return created;
}View on GitHub (pinned to fad1729dce)
Solutions
- Check the named table/column in the message against the entity mapping (typos, physical naming strategy, secondary table assignment)
- Remove or align custom @SQLInsert/@SQLUpdate/@SQLDelete annotations so their parameter placeholders match the mapped columns
- Reproduce with a minimal entity and report/upgrade: several 'Unable to locate parameter' bugs in JOINED/secondary-table mutation handling were fixed across 6.2-6.6 patches — move to the latest patch release
- Toggle @DynamicUpdate/@DynamicInsert off to see whether the optional-mutation path changes the failure
Example fix
// before: custom SQL parameter list disagrees with mapping @SQLUpdate(sql = "UPDATE doc SET content = ? WHERE id = ?") // after: match mapped columns (incl. version/tenant columns) or drop the custom SQL @SQLUpdate(sql = "UPDATE doc SET content = ?, version = ? WHERE id = ? AND version = ?")
Defensive patterns
Strategy: validation
Validate before calling
// validate custom SQL placeholders against mapped columns at boot
for (MappedColumn col : mappedColumns(entity)) {
if (!customSql.contains(col.placeholder())) {
throw new IllegalStateException("custom SQL missing parameter for " + col.name());
}
} Try / catch
try {
session.flush();
}
catch (UnknownParameterException e) {
// e names table.column, usage and mutation type: compare against mapping
log.error("mapping mismatch: {}", e.getMessage());
} Prevention
- Keep custom @SQLInsert/@SQLUpdate in lockstep with mapping changes (review in PRs)
- Re-test secondary-table and inheritance mappings after Hibernate upgrades
- Stay on the latest 6.x patch release where binding bugs are fixed
When it happens
Trigger: Binding a column that is not part of the mapped mutation for that table: secondary-table (@Table/@SecondaryTable) or JOINED-inheritance mappings where the attribute/table split disagrees with the mutation SQL, custom @SQLInsert/@SQLUpdate/@SQLDelete with mismatched parameter lists, or optimizer/dynamic-update paths that drop a parameter (several were Hibernate 6 bugs).
Common situations: After upgrading Hibernate 6.x point releases with JOINED inheritance or secondary tables; entities with @DynamicUpdate plus soft-delete/@Where; hand-written custom SQL mutation annotations whose placeholders no longer match the mapping.
Related errors
- Unable to locate JdbcValueDescriptor for column `%s`
- write expression must contain exactly one value placeholder
- Could not locate binding [%s : %s]
- Unable to locate parameter `%s.%s` for %s - %s : %s
- The INSERT statement for table [%s] contains no column, and
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/b17494af46fa752c.
Report an issue: GitHub.