{"record":{"id":"0f50734937d93265","repo":"hibernate/hibernate-orm","slug":"can-t-parse-json-object-for-selectable-s-which","errorCode":null,"errorMessage":"Can't parse JSON object for selectable [%s] which is not of type AggregateJdbcType.","messagePattern":"Can't parse JSON object for selectable \\[(.+?)\\] which is not of type AggregateJdbcType\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JsonHelper.java","lineNumber":132,"sourceCode":"\t\t\t\tcase ARRAY_END -> {\n\t\t\t\t\tassert currentLevel.arrayType != null;\n\t\t\t\t\tassert currentLevel.selectableData != null;\n\n\t\t\t\t\tparseLevel.pop();\n\t\t\t\t\tfinal ParseLevel parentLevel = parseLevel.getCurrent();\n\n\t\t\t\t\tassert parentLevel.embeddableMappingType != null;\n\t\t\t\t\t// flush array values\n\t\t\t\t\tparentLevel.addValue(\n\t\t\t\t\t\t\tcurrentLevel.selectableData,\n\t\t\t\t\t\t\tcurrentLevel.arrayType.getJdbcJavaType().wrap( currentLevel.subArrayObjectList, options )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcase OBJECT_START -> {\n\t\t\t\t\tfinal JdbcMapping jdbcMapping = currentLevel.determineJdbcMapping( currentSelectableData );\n\n\t\t\t\t\tif ( !(jdbcMapping.getJdbcType() instanceof AggregateJdbcType aggregateJdbcType) ) {\n\t\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\t\t\t\"Can't parse JSON object for selectable [%s] which is not of type AggregateJdbcType.\",\n\t\t\t\t\t\t\t\t\t\tParseLevel.determineSelectablePath( parseLevel, currentSelectableData )\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tparseLevel.push(\n\t\t\t\t\t\t\tnew ParseLevel( currentSelectableData, aggregateJdbcType.getEmbeddableMappingType() ) );\n\t\t\t\t\tcurrentSelectableData = null;\n\t\t\t\t}\n\t\t\t\tcase OBJECT_END -> {\n\t\t\t\t\tfinal EmbeddableMappingType currentEmbeddableMappingType = currentLevel.embeddableMappingType;\n\t\t\t\t\tassert currentEmbeddableMappingType != null;\n\n\t\t\t\t\t// go back in the mapping definition tree\n\t\t\t\t\tparseLevel.pop();\n\t\t\t\t\tfinal Object objectValue;\n\t\t\t\t\tif ( returnEmbeddable ) {","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JsonHelper.java#L114-L150","documentation":"While parsing a JSON document into an embeddable, encountering OBJECT_START for a selectable whose JdbcType is not an AggregateJdbcType throws IllegalArgumentException - the document has a nested JSON object where the mapping expects a basic/scalar value (nested objects are only legal for nested embeddables mapped as aggregates).","triggerScenarios":"Loading a json/struct aggregate mapping where the stored document nests an object under a key mapped to a scalar attribute; e.g., {\"price\":{\"amount\":1,\"currency\":\"EUR\"}} while 'price' is mapped as a plain BigDecimal column, not an embedded Money type.","commonSituations":"Refactoring an embeddable by flattening or un-flattening nested objects without migrating stored JSON; multiple writers (some embedding, some not) sharing the column.","solutions":["Model the nested object: add an @Embeddable class for it and annotate the attribute so it is aggregate-mapped (@Embedded + json/struct mapping), making its JdbcType an AggregateJdbcType.","Or flatten the stored data so the key holds a scalar instead of an object."],"exampleFix":"// before: stored {\"price\":{\"amount\":1.0,\"currency\":\"EUR\"}} but attribute is scalar\n@Embeddable public class Product { BigDecimal price; }\n// load -> Can't parse JSON object for selectable [price]\n\n// after: map the nested object as an aggregate embeddable\n@Embeddable public class Product {\n    @Embedded\n    Money price;   // @Embeddable class Money { BigDecimal amount; String currency; }\n}","handlingStrategy":"validation","validationCode":"// Check nested objects only appear under aggregate-mapped keys (Jackson example)\nstatic void assertObjectsOnlyOnAggregateKeys(JsonNode doc, Set<String> aggregateKeys) {\n    doc.fields().forEachRemaining(entry -> {\n        if (entry.getValue().isObject() && !aggregateKeys.contains(entry.getKey())) {\n            throw new IllegalStateException(\"Key '\" + entry.getKey() + \"' holds an object but is not an aggregate/embeddable\");\n        }\n    });\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.find(Product.class, id);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"not of type AggregateJdbcType\")) {\n        // nested object vs scalar mapping: add an @Embeddable for it or flatten the data\n    } else {\n        throw e;\n    }\n}","preventionTips":["Model nested JSON objects as @Embeddable aggregates, not scalars","Migrate stored JSON when flattening/unflattening embeddables","Document which keys may nest objects in the mapping's Javadoc"],"tags":["hibernate","json","embeddable","aggregate-mapping","type-mismatch"],"backgroundTag":"json-mapping-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}