{"record":{"id":"c79a28551a1805ad","repo":"hibernate/hibernate-orm","slug":"array-not-properly-formed","errorCode":null,"errorMessage":"Array not properly formed: {}","messagePattern":"Array not properly formed: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/type/AbstractPostgreSQLStructJdbcType.java","lineNumber":967,"sourceCode":"\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tvalues.add(\n\t\t\t\t\t\t\t\t\t\tfromString(\n\t\t\t\t\t\t\t\t\t\t\t\telementType,\n\t\t\t\t\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\t\t\t\t\tstart,\n\t\t\t\t\t\t\t\t\t\t\t\ti\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn i + 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthrow new IllegalArgumentException( \"Array not properly formed: \" + string.substring( start ) );\n\t}\n\n\tprivate SelectableMapping getJdbcValueSelectable(int jdbcValueSelectableIndex) {\n\t\treturn embeddableMappingType.getJdbcValueSelectable(\n\t\t\t\torderMapping != null ? orderMapping[jdbcValueSelectableIndex] : jdbcValueSelectableIndex );\n\t}\n\n\tprivate static boolean repeatsChar(String string, int start, int times, char expectedChar) {\n\t\tfinal int end = start + times;\n\t\tif ( end < string.length() ) {\n\t\t\tfor ( ; start < end; start++ ) {\n\t\t\t\tif ( string.charAt( start ) != expectedChar ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;","sourceCodeStart":949,"sourceCodeEnd":985,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/type/AbstractPostgreSQLStructJdbcType.java#L949-L985","documentation":"Thrown by Hibernate's PostgreSQL struct/array support while parsing the text literal of a PostgreSQL array or composite value (e.g. \"{1,2,3}\" or a nested \"(1,(2,3))\" ROW literal). The parser in AbstractPostgreSQLStructJdbcType walks the string character by character; when it cannot find a well-formed element list (unmatched braces/quotes/parens, an unexpected character, a stray separator), it gives up and reports the unconsumed substring. The text after the colon is the exact part of the literal the parser could not digest, which pinpoints the malformed element.","triggerScenarios":"Reading or binding an attribute mapped as a PostgreSQL array or @Struct (SqlTypes.ARRAY / SqlTypes.STRUCT) whose string literal is malformed: elements containing unquoted commas, braces or double quotes; single instead of doubled quotes inside quoted elements; backslash escapes written by a non-JDBC writer; nested struct literals with mismatched parentheses; NULL spelled in a non-standard way; data written by COPY, an ETL tool, or a different driver and later read through Hibernate.","commonSituations":"PostgreSQL composite/array columns populated by external ETL or string-concatenating SQL that skips PostgreSQL quoting rules; corrupted rows where the literal was truncated; Hibernate version changes that tightened or loosened the struct-literal parser; entity graphs combining @Struct embeddables with nested arrays.","solutions":["Copy the substring shown after 'Array not properly formed:' and compare it against PostgreSQL array-literal rules: quote any element containing , { } \" or \\ and double embedded quotes.","Inspect and repair the stored data: SELECT the column ::text to see the exact literal the parser saw, then fix the offending rows or re-write them through proper parameter binding.","If another writer produces these values, change it to build literals with array_to_string/row(...) or to bind java.sql.Array values instead of concatenating strings.","Upgrade Hibernate ORM - the AbstractPostgreSQLStructJdbcType literal parser receives fixes for escaped quotes and nested literals across releases.","As a workaround, map the attribute as String (or through an AttributeConverter) and parse the literal yourself."],"exampleFix":"// before: writer stored an element containing '{' unquoted\n//   UPDATE t SET arr = '{a,b{1,2},c}'      -- breaks the parser at 'b{1,2}'\n// after: quote the element per PostgreSQL rules\n//   UPDATE t SET arr = '{a,\"b{1,2}\",c}'\n// or better, let the driver build the literal:\n//   session.createNativeQuery(\"update t set arr = :arr\")\n//          .setParameter(\"arr\", List.of(\"a\", \"b{1,2}\", \"c\"));","handlingStrategy":"validation","validationCode":"// Before exposing external strings to a PostgreSQL array/struct mapping, sanity-check the literal:\nstatic boolean looksLikeValidArrayLiteral(String s) {\n    if (s == null || s.isEmpty()) return false;\n    int depth = 0; boolean inQuote = false;\n    for (int i = 0; i < s.length(); i++) {\n        char c = s.charAt(i);\n        if (inQuote) { if (c == '\"' && i + 1 < s.length() && s.charAt(i + 1) == '\"') i++; else if (c == '\"') inQuote = false; continue; }\n        if (c == '\"') inQuote = true;\n        else if (c == '{' || c == '(') depth++;\n        else if (c == '}' || c == ')') { depth--; if (depth < 0) return false; }\n    }\n    return depth == 0 && !inQuote;\n}","typeGuard":null,"tryCatchPattern":"catch (HibernateException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Array not properly formed:\")) {\n        // message suffix = offending literal fragment; correlate with the row and route to a data-repair path\n        throw new DataQualityException(\"Bad array literal: \" + e.getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Always write array/struct values through JDBC parameter binding (java.sql.Array / typed setters) so PostgreSQL generates well-formed literals itself.","Validate externally produced array literals (brace/quote balance) before storing them where Hibernate will read.","Add a checksum/QA query after bulk loads: count rows whose ::text literal fails a regex shape test."],"tags":["postgresql","array","struct","parsing","jdbc-type","composite-type"],"backgroundTag":"postgresql-array-literal-parse","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}