{"record":{"id":"cc0257fe593a55ca","repo":"quarkusio/quarkus","slug":"first-char-must-be-in-range-0-255-but-was","errorCode":null,"errorMessage":"First char must be in range [0, 255] but was: ","messagePattern":"First char must be in range \\[0, 255\\] but was: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"independent-projects/qute/core/src/main/java/io/quarkus/qute/JsonEscaper.java","lineNumber":36,"sourceCode":"     * The replacement data is packed as follows:<br>\n     * write an ASCII art of the int:<br>\n     * The visual order chosen reflect what Integer::toHexString would print since Java ints are stored big-endian.<br>\n     *\n     * <pre>\n     *         |----------|-----------|-------------|------------|\n     *  bits   |   24-31  |   16-23   |    8-15     |    0-7     |\n     *  field  |  length  |  padding  |   2nd char  |  1st char  |\n     *  values |  {1,2,6} |    [0]    |   [0-255]   |   [0-255]  |\n     *         |----------|-----------|-------------|------------|\n     * </pre>\n     *\n     */\n    private static int packReplacementData(int first, int second, int length) {\n        if (length != 1 && length != 2 && length != 6) {\n            throw new IllegalArgumentException(\"Length must be 1, 2 or 6 but was: \" + length);\n        }\n        if (first < 0 || first > 255) {\n            throw new IllegalArgumentException(\"First char must be in range [0, 255] but was: \" + first);\n        }\n        if (second < 0 || second > 255) {\n            throw new IllegalArgumentException(\"Second char must be in range [0, 255] but was: \" + second);\n        }\n        return (first | (second << SECOND_CHAR_OFFSET)) | (length << LENGTH_BITS_OFFSET);\n    }\n\n    private static int replacementLength(int replacementData) {\n        // length isn't bigger than 127, which means preserving sign (which is faster) won't affect the shift\n        return replacementData >> LENGTH_BITS_OFFSET;\n    }\n\n    private static char secondChar(int replacementData) {\n        // since past the second char we have padding === 0 we can just cast to char\n        return (char) (replacementData >> SECOND_CHAR_OFFSET);\n    }\n\n    private static char firstChar(int replacementData) {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/qute/core/src/main/java/io/quarkus/qute/JsonEscaper.java#L18-L54","documentation":"JsonEscaper bit-packs escape metadata into one int: 'first' occupies the low 8 bits (range [0,255]). Passing a char code above 255 or negative would collide with the 'second' and 'length' bit fields, corrupting the packed data, so IllegalArgumentException is thrown. Used when building JSON escape replacement tables.","triggerScenarios":"Calling the private packReplacementData with first < 0 or first > 255 — e.g. packing a non-ASCII char directly (code point > 255) instead of encoding it as a 6-char unicode escape.","commonSituations":"Adding a new escape entry for a non-Latin-1 character (e.g. '€') as a raw first char instead of going through the \\uXXXX path; not reachable from user templates.","solutions":["Clamp/validate input: only chars 0–255 may go into 'first'; handle higher code points via the unicode escape (length 6) path","Compute first from replacement.charAt(0) only after verifying it is <= 255","If non-ASCII escapes are needed, extend the escaper to always emit \\uXXXX form for those characters"],"exampleFix":"// before\npackReplacementData('€', 'x', 1); // 0x20AC > 255, throws\n// after\npackReplacementData('\\\\', 'u20AC'.charAt(0), 6); // use unicode escape representation","handlingStrategy":"validation","validationCode":"if (first < 0 || first > 255) {\n    throw new IllegalArgumentException(\"first must be in [0,255]: \" + first);\n}","typeGuard":"boolean isLatin1(char c) {\n    return c >= 0 && c <= 255;\n}","tryCatchPattern":"try {\n    int packed = packReplacementData(first, second, length);\n} catch (IllegalArgumentException e) {\n    log.error(\"Escape char out of range: \" + e.getMessage());\n    throw e;\n}","preventionTips":["Encode non-Latin-1 characters as \\uXXXX (length 6) instead of raw chars","Range-check chars before packing","Test escaper tables with ASCII-only fixtures"],"tags":["qute","json","escaping","internal","bit-packing"],"backgroundTag":"invalid-argument-range","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}