{"record":{"id":"bd229ec430018ee8","repo":"hibernate/hibernate-orm","slug":"unexpected-continuation-of-locale-value-after-exte","errorCode":null,"errorMessage":"Unexpected continuation of locale value after extension: %s","messagePattern":"Unexpected continuation of locale value after extension: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/java/LocaleJavaType.java","lineNumber":153,"sourceCode":"\t\t\t\t}\n\t\t\t\tcase SCRIPT -> {\n\t\t\t\t\tif ( length < 5 || chars[start] != '#' ) {\n\t\t\t\t\t\tthrow new IllegalArgumentException( \"Invalid script: \" + new String( chars, start, length ) );\n\t\t\t\t\t}\n\t\t\t\t\tif ( isScript( chars, start + 1, length - 1 ) ) {\n\t\t\t\t\t\tbuilder.setScript( new String( chars, start + 1, length - 1 ) );\n\t\t\t\t\t\tyield EXTENSION;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\thandleExtension( chars, start + 1, length - 1, builder );\n\t\t\t\t\t\tyield END;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcase EXTENSION -> {\n\t\t\t\t\thandleExtension(  chars, start, length, builder );\n\t\t\t\t\tyield END;\n\t\t\t\t}\n\t\t\t\tcase END -> throw new IllegalStateException( \"Unexpected continuation of locale value after extension: \" + new String( chars, start, length ) );\n\t\t\t};\n\t\t}\n\n\t\tprivate boolean isScript(char[] chars, int start, int length) {\n\t\t\treturn length == 4\n\t\t\t\t&& isLetter( chars[start] )\n\t\t\t\t&& isLetter( chars[start + 1] )\n\t\t\t\t&& isLetter( chars[start + 2] )\n\t\t\t\t&& isLetter( chars[start + 3] );\n\t\t}\n\n\t\tprivate void handleExtension(char[] chars, int start, int length, Locale.Builder builder) {\n\t\t\tif ( length < 3 || chars[start + 1] != '-' ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Invalid extension: \" + new String( chars, start, length ) );\n\t\t\t}\n\t\t\tif ( toLowerCase( chars[start] ) == 'u' ) {\n\t\t\t\t// After a Unicode extension, there could come a private use extension which we need to detect\n\t\t\t\tint unicodeStart = start + 2;","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/LocaleJavaType.java#L135-L171","documentation":"The locale parsing state machine reaches state END after an extension segment has been consumed; the grammar allows nothing after language_region_variant#Script_extension. If another underscore-separated segment follows, parseNext throws IllegalStateException(\"Unexpected continuation of locale value after extension: ...\"). It indicates the stored locale value has more segments than the format supports, not a transient condition.","triggerScenarios":"Values like 'en_US_var#Latn_u-ca-gregory_extra' (extra segment after the extension); tooling that appends suffixes ('_backup', '_v2') to stored locale codes; double-appending extensions by string concatenation ('..._u-ca-gregory_x-foo_more').","commonSituations":"Locale columns abused to carry extra metadata; data migrations that concatenated fields; admin tools letting free-form strings into the column.","solutions":["Remove the extra segments; move auxiliary metadata to a separate column","Use BCP 47 language tags ('en-US') which are routed to Locale.Builder.setLanguageTag and handle extensions correctly","Validate with Locale.forLanguageTag(...)/Locale.Builder before saving","Segment-count check on write: at most 4 underscore-separated parts for the legacy grammar"],"exampleFix":"// before\nString stored = \"en_US_posix#Latn_u-ca-gregory_backup\"; // IllegalStateException\n\n// after\nString stored = \"en-US-u-ca-gregory\"; // proper BCP 47 tag\n// metadata 'backup' moved to its own column","handlingStrategy":"validation","validationCode":"static boolean hasAtMostFourUnderscoreSegments(String s) {\n    return s.chars().filter(c -> c == '_').count() <= 3;\n}\n\n// legacy grammar: lang_region_variant#script-ext -> max 3 underscores outside '#'\nif (!hasAtMostFourUnderscoreSegments(value)) reject(value);","typeGuard":null,"tryCatchPattern":"catch (IllegalStateException e) {\n    // \"Unexpected continuation of locale value after extension\"\n    throw new IllegalArgumentException(\"Too many segments in locale value: \" + value, e);\n}","preventionTips":["Never append suffixes/metadata to locale codes; use a separate column","Round-trip validate stored locales after bulk imports","Prefer BCP 47 tags which fail fast and clearly via Locale.Builder"],"tags":["hibernate","locale","parsing","state-machine","illegalstateexception"],"backgroundTag":"invalid-locale-format","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}