{"record":{"id":"22e1e50d81eecf0f","repo":"quarkusio/quarkus","slug":"second-char-must-be-in-range-0-255-but-was","errorCode":null,"errorMessage":"Second char must be in range [0, 255] but was: ","messagePattern":"Second 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":39,"sourceCode":"     *\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) {\n        // we need to filter the first byte\n        return (char) (replacementData & 0xFF);\n    }","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/qute/core/src/main/java/io/quarkus/qute/JsonEscaper.java#L21-L57","documentation":"JsonEscaper bit-packs escape metadata into one int: 'second' occupies bits SECOND_CHAR_OFFSET..LENGTH_BITS_OFFSET-1, requiring a value in [0,255]. A negative or >255 second char would overflow into the length field and corrupt the packed replacement data, so IllegalArgumentException is thrown.","triggerScenarios":"Calling the private packReplacementData with second < 0 or second > 255 — e.g. passing a non-ASCII character as the second char of a replacement pair.","commonSituations":"Extending Qute's JSON escape tables with multi-char replacements containing non-Latin-1 characters; only reachable when modifying escaper internals, not from templates.","solutions":["Ensure the second char is ASCII/Latin-1 (0–255) or use the \\uXXXX (length 6) representation for non-ASCII","Derive second via replacement.charAt(1) after a range check, and skip/restructure entries that exceed 255","If wider escapes are needed, redesign the packing offsets rather than passing out-of-range values"],"exampleFix":"// before\npackReplacementData('\\\\', 'é', 2); // 0xE9 fits, but '€' (0x20AC) would throw\n// after\npackReplacementData('\\\\', 'u', 6); // encode as \\uXXXX instead","handlingStrategy":"validation","validationCode":"if (second < 0 || second > 255) {\n    throw new IllegalArgumentException(\"second must be in [0,255]: \" + second);\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":["Keep replacement characters within Latin-1 or use \\uXXXX form","Range-check every char of a replacement before packing","Cover multi-char replacements in tests"],"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-12T22:17:10.623Z"}