hibernate/hibernate-orm · error · TransientPropertyValueException
Instance of '%s' references an unsaved transient instance of
Error message
Instance of '%s' references an unsaved transient instance of '%s' (persist the transient instance before flushing)
What it means
The graph-based flush planner tracks inserts whose non-nullable FK targets are still transient (Decomposer.trackUnresolvedInsert). If the dependencies are never satisfied by the end of planning, Decomposer throws TransientPropertyValueException ("Instance of 'A' references an unsaved transient instance of 'B' (persist the transient instance before flushing)", Decomposer.java:478). It is the graph-queue equivalent of the classic unresolved-insert failure: a mandatory association points at an unsaved entity and nothing cascades or persists it.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/action/queue/internal/decompose/Decomposer.java:478
return;
}
// Get first unresolved insert for error reporting
final var firstEntry = unresolvedInserts.entrySet().iterator().next();
final AbstractEntityInsertAction firstInsert = firstEntry.getKey();
final NonNullableTransientDependencies dependencies = firstEntry.getValue();
// Get first transient dependency for error message
final Object firstTransient = dependencies.getNonNullableTransientEntities().iterator().next();
final String firstPropertyPath = dependencies.getNonNullableTransientPropertyPaths(firstTransient).iterator().next();
final String entityName = firstInsert.getEntityName();
final String transientEntityName = session.guessEntityName(firstTransient);
// Log all unresolved dependencies for debugging
logUnresolvedDependencies();
throw new TransientPropertyValueException(
"Instance of '" + entityName +
"' references an unsaved transient instance of '" + transientEntityName +
"' (persist the transient instance before flushing)",
transientEntityName,
entityName,
firstPropertyPath
);
}
/// Log details about all unresolved dependencies for debugging purposes.
private void logUnresolvedDependencies() {
// Log via ActionLogger or similar when available
// For now, just track the data for error reporting
// The error message already includes the first unresolved dependency
}
/// Clear all tracked unresolved inserts. Used for cleanup.
public void clear() {View on GitHub (pinned to fad1729dce)
Solutions
- Add CascadeType.PERSIST (typically {PERSIST, MERGE}) to the association that references the transient instance
- Or persist the referenced entity explicitly before flush: session.persist(child) then flush
- If the reference is optional at flush time, make the column/property nullable and populate it in a later step
- If dependencies should be resolvable and are not, verify cascade reaches the instance through the exact path you traverse (cascades only follow mapped associations)
Example fix
// before - required tag never persisted; graph flush throws TransientPropertyValueException
Article a = new Article();
a.setTag(new Tag("java")); // @ManyToOne(optional=false), no cascade
em.persist(a);
em.flush();
// after - cascade the persist through the association
@ManyToOne(optional = false, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Tag tag; Defensive patterns
Strategy: validation
Validate before calling
// validate required references before flushing the graph
if (article.getTag() != null && !em.contains(article.getTag())) {
em.persist(article.getTag()); // satisfies the non-null FK dependency
}
em.persist(article);
em.flush(); Type guard
static boolean isTransient(Object entity, EntityManager em) {
return entity != null && !em.contains(entity);
} Try / catch
try {
em.flush();
} catch (TransientPropertyValueException e) {
// property path tells you exactly which association was unsaved
// fix cascade/persist, then rerun the use case in a fresh transaction
} Prevention
- Cascade {PERSIST, MERGE} on required associations created in the same unit of work
- If enabling hibernate.flush.queue.graph.defer_identity_inserts=true, test graphs that mix IDENTITY ids and required FKs
- Build aggregates through factory methods that link children to a persisted parent only
When it happens
Trigger: Setting a non-nullable @ManyToOne to a brand-new entity without CascadeType.PERSIST and flushing under the graph queue (default in 8.x); IDENTITY inserts deferred via hibernate.flush.queue.graph.defer_identity_inserts=true whose transient FK dependencies are never resolved; object graphs assembled in the wrong direction (only the many-side persisted).
Common situations: Same as classic TransientPropertyValueException: missing cascade after mapping refactor; builders/tests persisting only the aggregate root while a required child reference is new; switching an association from nullable to mandatory without adding cascade; enabling deferred identity inserts on 8.x exposing previously hidden ordering gaps.
Related errors
- Instance of '" + entityName + "' references an unsaved trans
- Decomposition not supported for %s
- Audit graph mutation plan used with non-graph action queue
- Audit graph mutation plan used with non-graph action queue
- cannot recreate collection while filter is enabled [%s : %s]
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/236afe3877f97a62.
Report an issue: GitHub.