{"record":{"id":"b3c2c3d613a08de1","repo":"hibernate/hibernate-orm","slug":"array-case-should-be-treated-at-upper-level","errorCode":null,"errorMessage":"array case should be treated at upper level","messagePattern":"array case should be treated at upper level","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/format/OsonDocumentWriter.java","lineNumber":244,"sourceCode":"\t\t\t\tbreak;\n\n\t\t\tcase SqlTypes.DURATION:\n\t\t\tcase SqlTypes.UUID:\n\t\t\t\tgenerator.write( javaType.toString( (T)value ) );\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// how to handle\n\t\t\t\tbyte[] bytes = javaType.unwrap( (T)value, byte[].class, options );\n\t\t\t\tgenerator.write( bytes );\n\t\t\t\tbreak;\n\t\t\tcase SqlTypes.ARRAY:\n\t\t\tcase SqlTypes.JSON_ARRAY:\n\t\t\t\tthrow new IllegalStateException( \"array case should be treated at upper level\" );\n\t\t\tdefault:\n\t\t\t\tthrow new UnsupportedOperationException( \"Unsupported JdbcType nested in JSON: \" + jdbcType );\n\t\t}\n\n\t}\n\n}\n","sourceCodeStart":226,"sourceCodeEnd":252,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/format/OsonDocumentWriter.java#L226-L252","documentation":"OsonDocumentWriter.serializeValue switches on the nested value's JDBC type code to render a JSON leaf. ARRAY and JSON_ARRAY are deliberately rejected with IllegalStateException 'array case should be treated at upper level': arrays must be written by JsonGeneratingVisitor.visitArray (startArray, per-element visit, endArray), never as a single leaf value. Reaching this branch means an array JdbcType was handed straight to the leaf serializer.","triggerScenarios":"A nested/multi-dimensional plural mapping where an element's own JdbcType still resolves to ARRAY or JSON_ARRAY - e.g. int[][], List<int[]>, or a JSON aggregate whose element is itself array-typed - serialized through the Oracle OSON writer during flush.","commonSituations":"Modeling matrix/nested-array data in JSON columns on Oracle; mapping changes that alter element-type resolution; version upgrades changing how plural elements are routed between the visitor and the writer.","solutions":["Flatten the structure - store List<ElementType> with a non-array element type, or wrap each nested array inside an embeddable","Map the whole nested structure as a single JSON value (@JdbcTypeCode(SqlTypes.JSON)) instead of per-element array types","Upgrade Hibernate ORM - routing between visitor and writer has received fixes; report with a mapping reproducer if it persists"],"exampleFix":"// before\n@JdbcTypeCode(SqlTypes.ARRAY)\nprivate int[][] matrix; // element JDBC type is again ARRAY -> 'array case should be treated at upper level'\n\n// after\n@JdbcTypeCode(SqlTypes.JSON)\nprivate List<List<Integer>> matrix; // one JSON document, no nested array JDBC types","handlingStrategy":"validation","validationCode":"// Startup check: no nested plural-of-plural mappings for JSON aggregates on Oracle\nint elementCode = elementJdbcType.getDefaultSqlTypeCode();\nif (elementCode == SqlTypes.ARRAY || elementCode == SqlTypes.JSON_ARRAY) {\n    throw new IllegalStateException(\"Nested array JDBC types cannot be serialized to JSON; flatten the mapping\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid multi-dimensional array mappings inside JSON aggregates","Wrap nested collections in embeddables or map the whole structure as one JSON value","Persist sample aggregate data on the target dialect in CI"],"tags":["hibernate","oracle","oson","json","array","nested-array","serialization"],"backgroundTag":"json-nested-array-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}