{"record":{"id":"c6e646ba92123994","repo":"hibernate/hibernate-orm","slug":"unexpected-json-array-type","errorCode":null,"errorMessage":"unexpected JSON array type","messagePattern":"unexpected JSON array type","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/format/StringJsonDocumentWriter.java","lineNumber":374,"sourceCode":"\t\t\t\tappender.append( StringJsonDocumentMarker.QUOTE.getMarkerCharacter() );\n\t\t\t\tjavaType.appendEncodedString( appender, (T) value );\n\t\t\t\tappender.append( StringJsonDocumentMarker.QUOTE.getMarkerCharacter() );\n\t\t\t\tbreak;\n\t\t\tcase SqlTypes.BINARY:\n\t\t\tcase SqlTypes.VARBINARY:\n\t\t\tcase SqlTypes.LONGVARBINARY:\n\t\t\tcase SqlTypes.LONG32VARBINARY:\n\t\t\tcase SqlTypes.BLOB:\n\t\t\tcase SqlTypes.MATERIALIZED_BLOB:\n\t\t\t\t// These types need to be serialized as JSON string, and for efficiency uses appendString directly\n\t\t\t\tappender.append( StringJsonDocumentMarker.QUOTE.getMarkerCharacter() );\n\t\t\t\tappender.write( javaType.unwrap( (T) value, byte[].class, options ) );\n\t\t\t\tappender.append( StringJsonDocumentMarker.QUOTE.getMarkerCharacter() );\n\t\t\t\tbreak;\n\t\t\tcase SqlTypes.ARRAY:\n\t\t\tcase SqlTypes.JSON_ARRAY:\n\t\t\t\t// Caller handles this. We should never end up here actually.\n\t\t\t\tthrow new IllegalStateException( \"unexpected JSON array type\" );\n\t\t\tdefault:\n\t\t\t\tthrow new UnsupportedOperationException( \"Unsupported JdbcType nested in JSON: \" + jdbcType );\n\t\t}\n\t}\n\n\tpublic String getJson() {\n\t\treturn appender.toString();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn appender.toString();\n\t}\n\n\tprivate static class JsonAppender extends OutputStream implements SqlAppender {\n\n\t\tprivate final static char[] HEX_ARRAY = \"0123456789ABCDEF\".toCharArray();\n","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/format/StringJsonDocumentWriter.java#L356-L392","documentation":"convertedBasicValueToString() serializes one nested attribute of a JSON aggregate and explicitly refuses JDBC types whose default SQL type code is SqlTypes.ARRAY or JSON_ARRAY — the comment states the caller must emit arrays via startArray()/values/endArray() instead. Reaching this throw means Hibernate's own serialization path routed an array-typed value into the scalar branch: an internal invariant break, not a user input error.","triggerScenarios":"An embeddable/aggregate mapped to JSON containing an attribute annotated @JdbcTypeCode(SqlTypes.ARRAY) or SqlTypes.JSON_ARRAY (List or primitive array) where the dialect's writer passes it into serializeJsonValue() instead of the array callbacks; typically on dialects with native JSON aggregate support (Oracle, DB2, SQL Server).","commonSituations":"Mapping a List<T>/T[] field inside a JSON aggregate with an array JdbcType; upgrading Hibernate across versions where JSON aggregate serialization was reworked; a custom JdbcType whose getDefaultSqlTypeCode() reports ARRAY.","solutions":["Remap the nested collection so Hibernate serializes it as JSON content (remove @JdbcTypeCode(SqlTypes.ARRAY)/JSON_ARRAY from the attribute)","Test against the latest 7.x patch release and search the HHH JIRA for 'unexpected JSON array type' — JSON aggregate handling has active fixes","Plug in a custom FormatMapper via hibernate.type.json_format_mapper that serializes the aggregate end-to-end","If reproducible on the latest release, report to Hibernate JIRA with the entity mapping and dialect"],"exampleFix":"// before\n@Embeddable\npublic class Details {\n    @JdbcTypeCode(SqlTypes.ARRAY)   // routed into scalar branch -> IllegalStateException\n    private List<String> tags;\n}\n// after\n@Embeddable\npublic class Details {\n    // let Hibernate map the collection inside the JSON document\n    private List<String> tags;\n}","handlingStrategy":"try-catch","validationCode":"// fail fast at startup: no aggregate attribute may use an array JdbcType\nstatic void checkAggregateAttributes(org.hibernate.metamodel.MappingMetamodel metamodel) {\n    metamodel.getEmbeddables().forEach(embeddable -> embeddable.getAttributes().forEach(attr -> {\n        // reject attributes resolved to SqlTypes.ARRAY / SqlTypes.JSON_ARRAY inside JSON aggregates\n    }));\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.merge(entity);\n    session.flush();\n} catch (IllegalStateException e) {\n    if (\"unexpected JSON array type\".equals(e.getMessage())) {\n        // Hibernate internal invariant: remap the nested collection attribute and retry\n        throw new MappingConfigurationException(\"Nested array attribute inside JSON aggregate is not supported - map it as JSON\", e);\n    }\n    throw e;\n}","preventionTips":["Do not combine @JdbcTypeCode(SqlTypes.ARRAY / JSON_ARRAY) with attributes nested in JSON aggregates","Integration-test aggregate writes (including nested collections) against the target dialect","Watch release notes when upgrading - JSON aggregate serialization evolves between Hibernate versions"],"tags":["hibernate","json","serialization","aggregate-mapping","array-type"],"backgroundTag":"unsupported-type-mapping","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}