hibernate/hibernate-orm · error · IllegalArgumentException
Could not find selectable [%s] in embeddable type [%s] for J
Error message
Could not find selectable [%s] in embeddable type [%s] for JSON processing.
What it means
When Hibernate reads a JSON-mapped embeddable (aggregate mapping), JsonHelper walks the JSON object and resolves each key against the embeddable's selectables with getSelectableIndex(name). A key with no matching selectable makes it throw IllegalArgumentException('Could not find selectable ...') - the stored JSON document and the mapped embeddable disagree about which properties exist.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JsonHelper.java:88
// that means that we have to stop parsing. That may be the case while parsing an object of object array,
// the array is not empty, but we ae done parsing that specific object.
// When we encounter OBJECT_END the current type is popped out of the stack. When parsing one object of an array we may end up
// having an empty stack. Next Objects are parsed in the next round.
while(reader.hasNext() && !parseLevel.isEmpty()) {
final ParseLevel currentLevel = parseLevel.getCurrent();
assert currentLevel != null;
switch (reader.next()) {
case VALUE_KEY -> {
final EmbeddableMappingType currentEmbeddableMappingType = currentLevel.embeddableMappingType;
assert currentEmbeddableMappingType != null
: "Value keys are only valid for objects";
assert currentSelectableData == null;
final String selectableName = reader.getObjectKeyName();
final int selectableIndex = currentEmbeddableMappingType.getSelectableIndex( selectableName );
if ( selectableIndex < 0 ) {
throw new IllegalArgumentException(
String.format(
"Could not find selectable [%s] in embeddable type [%s] for JSON processing.",
selectableName,
currentEmbeddableMappingType.getMappedJavaType().getJavaTypeClass().getName()
)
);
}
final SelectableMapping selectableMapping =
currentEmbeddableMappingType.getJdbcValueSelectable( selectableIndex );
currentSelectableData = new SelectableData( selectableName, selectableIndex, selectableMapping );
}
case ARRAY_START -> {
assert currentSelectableData != null;
if ( !(currentSelectableData.selectableMapping.getJdbcMapping() instanceof BasicPluralType<?, ?> pluralType) ) {
throw new IllegalArgumentException(
String.format(
"Can't parse JSON array for selectable [%s] which is not of type BasicPluralType.",View on GitHub (pinned to fad1729dce)
Solutions
- Migrate the stored JSON documents to match the current embeddable (rename/remove the extra keys, e.g. UPDATE ... SET doc = doc - 'legacyKey' on Postgres jsonb).
- Or extend the embeddable so every stored key maps to a selectable (add the missing attribute).
- Configure the writing side (custom JsonFormatMapper) to emit only mapped attributes so future documents stay clean.
- For JSON columns shared across applications, read them through a versioned DTO instead of the strict embeddable mapping.
Example fix
// before: stored {"name":"x","legacyCode":"y"} but embeddable maps only 'name'
@Embeddable public class Address { String name; }
// load -> Could not find selectable [legacyCode]
// after: either migrate the data or map the extra key
@Embeddable public class Address {
String name;
@Column(name = "legacy_code") String legacyCode;
}
// or: UPDATE entity_table SET doc = doc - 'legacyCode'; Defensive patterns
Strategy: validation
Validate before calling
// Validate the document before Hibernate reads it (Jackson example)
static void checkJsonKeysAgainstEmbeddable(com.fasterxml.jackson.databind.JsonNode doc,
Set<String> mappedAttributeNames) {
doc.fieldNames().forEachRemaining(key -> {
if (!mappedAttributeNames.contains(key)) {
throw new IllegalArgumentException("Unmapped JSON key in stored document: " + key);
}
});
} Try / catch
try {
return session.find(Product.class, id);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Could not find selectable")) {
// message names the unmapped key and embeddable: migrate the JSON column or add the attribute
} else {
throw e;
}
} Prevention
- Migrate stored JSON whenever embeddable attributes are renamed or removed
- Configure the writing JsonFormatMapper to emit only mapped properties
- Validate JSON documents against the mapping in a CI test with production-like data
When it happens
Trigger: Loading an entity whose JSON column contains keys that have no corresponding attribute/column in the @Embeddable: an attribute was renamed or removed, or the JSON was written by another service, a custom JsonFormatMapper, or by hand.
Common situations: Schema drift between microservices sharing a JSON column; renaming an embeddable field without migrating stored documents; custom Jackson-based format mappers serializing extra properties (mixins, @JsonAnyGetter); test fixtures with hand-written JSON.
Related errors
- Can't parse JSON object for selectable [%s] which is not of
- Failed to serialize JSON mapping
- Support for model part type not yet implemented:
- Unwrap strategy not known for this Java type: " + getTypeNam
- Wrap strategy not known for this Java type: " + getTypeName(
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/5de19d5ba28e3b11.
Report an issue: GitHub.