hibernate/hibernate-orm · error · FetchNotFoundException

Entity `%s` with identifier value `%s` does not exist

Error message

Entity `%s` with identifier value `%s` does not exist

What it means

The not-filtered fallback in JoinedDiscriminatedEntityInitializer: after resolving a to-one association to a JOINED-inheritance target via join, the FK is non-null but no concrete subclass row was found, no filter explains it, and NotFoundAction is EXCEPTION - so FetchNotFoundException('Entity X with identifier value Y does not exist') is thrown. The FK references a hierarchy instance whose row(s) are absent from the joined result.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/JoinedDiscriminatedEntityInitializer.java:218

		final Object foreignKeyValue = keyValueAssembler.assemble( data.getRowProcessingState() );
		if ( foreignKeyValue != null ) {
			final var concreteInitializer = concreteInitializersByEntityName.get( entityName );
			final boolean filteredOut;
			if ( concreteInitializer == null ) {
				// Discriminator is null, but foreign key is given. Let's just assume this was filtered out,
				// if any initializer was affected by a filter
				filteredOut = !affectedByFilter.isEmpty();
			}
			else {
				final var index = ArrayHelper.indexOf( concreteInitializers, concreteInitializer );
				assert index >= 0;
				filteredOut = affectedByFilter.get( index );
			}
			if ( filteredOut ) {
				throw new EntityFilterException( entityName, foreignKeyValue,
						fetchedPart.getNavigableRole().getFullPath() );
			}
			throw new FetchNotFoundException( entityName, foreignKeyValue );
		}
	}

	@Override
	public void resolveFromPreviousRow(JoinedDiscriminatedEntityInitializerData data) {
		if ( data.getState() == State.UNINITIALIZED ) {
			if ( data.getInstance() == null ) {
				data.setState( State.MISSING );
			}
			else {
				final var initializer = keyValueAssembler.getInitializer();
				if ( initializer != null ) {
					initializer.resolveFromPreviousRow( data.getRowProcessingState() );
				}
				if ( data.concreteInitializer != null ) {
					data.concreteInitializer.resolveFromPreviousRow( data.getRowProcessingState() );
				}
				data.setState( State.INITIALIZED );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Find and repair inconsistent hierarchy rows: FKs pointing at ids with no base row at all, and base rows without their subclass row.
  2. Add FOREIGN KEY constraints for both the base table PK relationships and each subclass table's FK to the base, so partial deletes are rejected.
  3. If absence is legal, use @NotFound(action = NotFoundAction.IGNORE) or optional=true so the association resolves to null.
  4. Re-check whether a filter was recently added - if so move to the EntityFilterException remedy, since that is the actual cause.

Example fix

-- find FKs with no base-table row
SELECT o.id, o.doc_id FROM "order" o LEFT JOIN document d ON d.id = o.doc_id
WHERE o.doc_id IS NOT NULL AND d.id IS NULL;

-- find JOINED hierarchies missing their subclass row
SELECT d.id FROM document d LEFT JOIN contract c ON c.id = d.id
WHERE d.dtype = 'CONTRACT' AND c.id IS NULL;

// before
@ManyToOne(optional = false)
private Document document;

// after
@ManyToOne
@NotFound(action = NotFoundAction.IGNORE)
private Document document;
Defensive patterns

Strategy: try-catch

Validate before calling

// Check JOINED hierarchy consistency + dangling FKs before loading
String base = "select o.id from \"order\" o left join document d on d.id = o.doc_id "
            + "where o.doc_id is not null and d.id is null";
String sub  = "select d.id from document d left join contract c on c.id = d.id "
            + "where d.dtype = 'CONTRACT' and c.id is null";
if (!em.createNativeQuery(base).getResultList().isEmpty()
        || !em.createNativeQuery(sub).getResultList().isEmpty()) {
    throw new IllegalStateException("inconsistent JOINED inheritance data");
}

Try / catch

try {
    List<Order> l = em.createQuery("select o from Order o join fetch o.document", Order.class).getResultList();
} catch (FetchNotFoundException e) {
    // e.getIdentifier() -> the doc id with no base/subclass row; repair or ignore
}

Prevention

When it happens

Trigger: A non-null FK to a JOINED inheritance entity whose base or subclass row is missing; deletes that removed the subclass row but left the base row (or vice versa); discriminator present but the corresponding subclass table row absent; no FK constraint to prevent the orphan.

Common situations: Partially deleted JOINED-inheritance data (base row without subclass row or the reverse); manual data surgery on inheritance tables; inconsistent restores; imports that wrote base rows but skipped subclass rows.

Related errors


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