{"record":{"id":"4c515a93d4a21494","repo":"hibernate/hibernate-orm","slug":"can-t-parse-json-array-for-selectable-s-which-i","errorCode":null,"errorMessage":"Can't parse JSON array for selectable [%s] which is not of type BasicPluralType.","messagePattern":"Can't parse JSON array for selectable \\[(.+?)\\] which is not of type BasicPluralType\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JsonHelper.java","lineNumber":104,"sourceCode":"\t\t\t\t\tfinal int selectableIndex = currentEmbeddableMappingType.getSelectableIndex( selectableName );\n\t\t\t\t\tif ( selectableIndex < 0 ) {\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\"Could not find selectable [%s] in embeddable type [%s] for JSON processing.\",\n\t\t\t\t\t\t\t\t\t\tselectableName,\n\t\t\t\t\t\t\t\t\t\tcurrentEmbeddableMappingType.getMappedJavaType().getJavaTypeClass().getName()\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\tfinal SelectableMapping selectableMapping =\n\t\t\t\t\t\t\tcurrentEmbeddableMappingType.getJdbcValueSelectable( selectableIndex );\n\t\t\t\t\tcurrentSelectableData = new SelectableData( selectableName, selectableIndex, selectableMapping );\n\t\t\t\t}\n\t\t\t\tcase ARRAY_START -> {\n\t\t\t\t\tassert currentSelectableData != null;\n\n\t\t\t\t\tif ( !(currentSelectableData.selectableMapping.getJdbcMapping() instanceof BasicPluralType<?, ?> pluralType) ) {\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 array for selectable [%s] which is not of type BasicPluralType.\",\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( new ParseLevel( currentSelectableData, pluralType ) );\n\t\t\t\t\tcurrentSelectableData = null;\n\t\t\t\t}\n\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","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JsonHelper.java#L86-L122","documentation":"While parsing a JSON document into an embeddable, encountering ARRAY_START for a selectable whose JdbcMapping is not a BasicPluralType throws IllegalArgumentException - the stored JSON holds an array where the mapping expects a scalar or embeddable. Example: the attribute is Integer but the column value is [1,2].","triggerScenarios":"Loading an aggregate/json-mapped embeddable whose stored document contains an array under a key mapped to a non-collection attribute; data written by an older mapping where the attribute was a List and later changed to a scalar without data migration (or vice versa).","commonSituations":"Changing an embeddable attribute between List<T> and T without migrating the JSON column; other applications writing arrays into the column; copy-pasted fixture data.","solutions":["If the attribute really is a collection, map it as one: List<T>/T[] with @JdbcTypeCode(SqlTypes.JSON) (a BasicPluralType) so ARRAY_START is legal.","If the attribute is scalar, fix the stored data to a scalar value instead of an array."],"exampleFix":"// before: data is {\"tags\":[\"a\",\"b\"]} but attribute is scalar\n@Embeddable public class Meta { String tags; }\n// load -> Can't parse JSON array for selectable [tags]\n\n// after: map it as the collection it is\n@Embeddable public class Meta {\n    @JdbcTypeCode(SqlTypes.JSON)\n    List<String> tags;\n}\n// or fix the data: UPDATE t SET doc = '{\"tags\":\"a,b\"}';","handlingStrategy":"validation","validationCode":"// Before relying on a load, check scalar keys do not hold arrays (Jackson example)\nstatic void assertNoArraysOnScalarKeys(JsonNode doc, Set<String> scalarKeys) {\n    for (String key : scalarKeys) {\n        JsonNode n = doc.get(key);\n        if (n != null && n.isArray()) {\n            throw new IllegalStateException(\"Key '\" + key + \"' holds an array but is mapped as scalar\");\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 BasicPluralType\")) {\n        // stored array vs scalar mapping: fix the attribute to a plural JSON type or migrate the data\n    } else {\n        throw e;\n    }\n}","preventionTips":["When changing an attribute between scalar and collection, migrate stored JSON in the same release","Map collection attributes with @JdbcTypeCode(SqlTypes.JSON) so arrays are legal","Seed test data from the same mapping that reads it"],"tags":["hibernate","json","embeddable","type-mismatch","collection-mapping"],"backgroundTag":"json-mapping-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}