{"record":{"id":"5fc29037a42be019","repo":"hibernate/hibernate-orm","slug":"value-must-contain-exactly-one-character-str","errorCode":null,"errorMessage":"value must contain exactly one character: '\" + string + \"'","messagePattern":"value must contain exactly one character: '\" \\+ string \\+ \"'","errorType":"exception","errorClass":"CoercionException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CharacterJavaType.java","lineNumber":38,"sourceCode":"\n\tpublic CharacterJavaType() {\n\t\tsuper( Character.class );\n\t}\n\n\t@Override\n\tpublic boolean useObjectEqualsHashCode() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic String toString(Character value) {\n\t\treturn value.toString();\n\t}\n\n\t@Override\n\tpublic Character fromString(CharSequence string) {\n\t\tif ( string.length() != 1 ) {\n\t\t\tthrow new CoercionException( \"value must contain exactly one character: '\" + string + \"'\" );\n\t\t}\n\t\treturn string.charAt( 0 );\n\t}\n\n\t@Override\n\tpublic boolean isInstance(Object value) {\n\t\treturn value instanceof Character;\n\t}\n\n\t@Override\n\tpublic Character cast(Object value) {\n\t\treturn (Character) value;\n\t}\n\n\t@Override\n\tpublic <X> X unwrap(Character value, Class<X> type, WrapperOptions options) {\n\t\tif ( value == null ) {\n\t\t\treturn null;","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CharacterJavaType.java#L20-L56","documentation":"CharacterJavaType.fromString requires a CharSequence of length exactly 1; an empty string or a multi-character sequence throws CoercionException('value must contain exactly one character'). It is the parsing path used when a Character attribute is hydrated from string data.","triggerScenarios":"A CHAR(n)/VARCHAR column feeding a Character attribute with values longer or shorter than one character; empty strings; string parameters bound to Character fields.","commonSituations":"DB CHAR columns whose padding survives the read (no trim) so values come back longer than 1; schema evolved from a wider string column without cleaning data; NOT NULL string columns defaulted to ''.","solutions":["Use CHAR(1)/NCHAR(1) and make sure stored values are exactly one character.","Clean the data: UPDATE t SET c = SUBSTRING(c FROM 1 FOR 1) WHERE CHAR_LENGTH(c) <> 1, and handle empty rows explicitly.","Add a converter that trims and defaults empty input to a chosen character."],"exampleFix":"-- before\nUPDATE users SET initial = 'AB'; -- later hydrate throws CoercionException\n\n-- after\nUPDATE users SET initial = SUBSTRING(initial FROM 1 FOR 1) WHERE CHAR_LENGTH(initial) > 1;\nDELETE-fallback or converter for '' rows:\n@Converter\npublic class CharConverter implements AttributeConverter<Character, String> {\n    public String convertToDatabaseColumn(Character c) { return c == null ? null : c.toString(); }\n    public Character convertToEntityAttribute(String s) { return (s == null || s.isEmpty()) ? ' ' : s.trim().charAt(0); }\n}","handlingStrategy":"validation","validationCode":"static boolean isSingleChar(String s) {\n    return s != null && s.length() == 1;\n}\n// guard: if (!isSingleChar(col)) col = normalize(col); // trim or default","typeGuard":"static Character toCharOrNull(String s) {\n    if (s == null || s.isEmpty()) return null;\n    String t = s.trim();\n    return t.isEmpty() ? null : Character.valueOf(t.charAt(0));\n}","tryCatchPattern":null,"preventionTips":["Use CHAR(1)/NCHAR(1) columns for Character attributes.","Trim and validate form input before persisting to Character fields.","Clean padded/legacy data when refactoring String columns to char(1)."],"tags":["hibernate","character","mapping","parsing"],"backgroundTag":"character-length-mapping","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}