hibernate/hibernate-orm · error · ExecutionException

JDBC parameter value not bound - %s

Error message

JDBC parameter value not bound - %s

What it means

This Hibernate build adds temporal (changeset-based) filtering: TemporalJdbcParameter binds the current changeset identifier as the JDBC parameter for temporal restrictions. The value comes from the session's LoadQueryInfluencers temporal identifier, falling back to the session's current changeset identifier. If both are null the parameter cannot be bound and bindParameterValue throws ExecutionException('JDBC parameter value not bound - ...TemporalJdbcParameter...').

Source

Thrown at hibernate-core/src/main/java/org/hibernate/sql/exec/internal/TemporalJdbcParameter.java:36

 *
 * @author Gavin King
 */
public class TemporalJdbcParameter extends SqlTypedMappingJdbcParameter {

	public TemporalJdbcParameter(SqlTypedMapping sqlTypedMapping) {
		super( sqlTypedMapping );
	}

	@Override
	public void bindParameterValue(PreparedStatement statement, int startPosition, JdbcParameterBindings jdbcParamBindings, ExecutionContext executionContext)
			throws SQLException {
		final SharedSessionContractImplementor session = executionContext.getSession();
		final Object temporalIdentifier = session.getLoadQueryInfluencers().getTemporalIdentifier();
		final Object currentChangesetIdentifier = temporalIdentifier != null
				? temporalIdentifier
				: session.getCurrentChangesetIdentifier();
		if ( currentChangesetIdentifier == null ) {
			throw new ExecutionException( "JDBC parameter value not bound - " + this );
		}
		final Object bindValue = getJdbcMapping().convertToRelationalValue( currentChangesetIdentifier );
		bindParameterValue( getJdbcMapping(), statement, bindValue, startPosition, executionContext );
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Set the temporal context before running the query: session.getLoadQueryInfluencers().setTemporalIdentifier(changesetId), or pass the temporal identifier through the session options
  2. Run the query inside the write transaction context that defines a current changeset identifier
  3. Disable temporal filtering for that query/session if temporal semantics are not intended
  4. Verify audit configuration: temporal restrictions must always be evaluated against a concrete changeset

Example fix

// before
List<Entity> rows = session.createQuery(...).list(); // temporal restriction, no changeset id -> throws

// after
session.getLoadQueryInfluencers().setTemporalIdentifier( AuditLog.ALL_CHANGESETS );
List<Entity> rows = session.createQuery(...).list();
Defensive patterns

Strategy: validation

Validate before calling

Object temporalId = session.getLoadQueryInfluencers().getTemporalIdentifier();
if ( temporalId == null && session.getCurrentChangesetIdentifier() == null ) {
    throw new IllegalStateException( "Set a temporal identifier before running temporal queries" );
}

Prevention

When it happens

Trigger: Executing a query with a temporal restriction on a session that has neither an explicit temporal identifier (LoadQueryInfluencers.setTemporalIdentifier(...)) nor a current changeset identifier (the session is not inside an audited write context that established one).

Common situations: Enabling temporal/audit query mode without configuring the changeset id; running temporal queries against a stateless session opened without temporal options; code paths that clear or never set the temporal context; mixing audit loaders with ordinary sessions.

Related errors


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