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

  1. Check the named table/column in the message against the entity mapping (typos, physical naming strategy, secondary table assignment)
  2. Remove or align custom @SQLInsert/@SQLUpdate/@SQLDelete annotations so their parameter placeholders match the mapped columns
  3. 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
  4. 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

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


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