hibernate/hibernate-orm · error · HibernateException

Unable to locate JdbcValueDescriptor for column `%s`

Error message

Unable to locate JdbcValueDescriptor for column `%s`

What it means

JdbcValueBindings.bindValue maps a (column, ParameterUsage) pair onto a parameter slot of the prepared mutation. When a bind template is active and findSlot(columnName, parameterUsage) returns null, the mutation statement has no parameter for that column/usage combination, so the value cannot be attached and HibernateException is thrown. It is almost always a name or usage mismatch between what the caller binds and what the mutation SQL declares.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/spi/bind/JdbcValueBindings.java:116

								Locale.ROOT,
								"Unable to bind parameter #%s - %s",
								slot.jdbcPosition(),
								valuesBySlot[i]
						)
				);
			}
		}
	}

	public static Object resolveValue(Object value) {
		return value instanceof DelayedValueAccess handle ? handle.get() : value;
	}

	public void bindValue(Object columnValue, String columnName, ParameterUsage parameterUsage) {
		if ( bindTemplate != null ) {
			final BindSlot slot = bindTemplate.findSlot( columnName, parameterUsage );
			if ( slot == null ) {
				throw new HibernateException( "Unable to locate JdbcValueDescriptor for column `" + columnName + "`" );
			}
			if ( !boundSlots[slot.index()] ) {
				valuesBySlot[slot.index()] = columnValue;
				boundSlots[slot.index()] = true;
			}
			return;
		}

		final var jdbcValueDescriptor = jdbcValueDescriptorAccess.resolveValueDescriptor(
				tableDescriptor.name(),
				columnName,
				parameterUsage
		);
		if ( jdbcValueDescriptor == null ) {
			throw new HibernateException( "Unable to locate JdbcValueDescriptor for column `" + columnName + "`" );
		}
		bindingGroup.bindValue( columnName, columnValue, jdbcValueDescriptor );
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Log the mutation SQL and bind exactly the column names it declares, including case and quoting.
  2. Pass the ParameterUsage that matches the parameter kind being bound (REGULAR, RETURNING, LIMIT...).
  3. In custom binding code, derive names from the template/descriptor set instead of hard-coded literals.
  4. If no custom code is involved, upgrade Hibernate - descriptor resolution regressions have occurred across versions.

Example fix

// before
bindings.bindValue(value, "ACCOUNT_ID", ParameterUsage.REGULAR); // mapped as 'accountId'
// after
bindings.bindValue(value, "accountId", ParameterUsage.REGULAR);
Defensive patterns

Strategy: validation

Validate before calling

// derive column names from the mapping instead of hard-coded literals
for (SelectableMapping col : mutationTarget.getSelectableMappings()) {
    bindings.bindValue(values.get(col.getSelectionExpression()), col.getSelectionExpression(), ParameterUsage.REGULAR);
}

Prevention

When it happens

Trigger: Calling bindValue with a column name that differs from the mapped name (case differences on case-sensitive databases, quoted identifiers, typos) or with the wrong ParameterUsage (e.g. binding a value as REGULAR when the parameter is RETURNING); custom mutation code binding columns that are not in the generated statement.

Common situations: Custom MutationExecutor / PreparableMutationOperation implementations; integrations that bind audit or revision columns; column renames in the mapping while stale code binds the old literal name.

Related errors


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