{"record":{"id":"2dba660d0554dd2e","repo":"nodejs/node","slug":"u-illegal-char-found","errorCode":"U_ILLEGAL_CHAR_FOUND","errorMessage":"Illegal Surrogate! ","messagePattern":"Illegal Surrogate! ","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"deps/icu-small/source/tools/genrb/wrtxml.cpp","lineNumber":263,"sourceCode":"    }\n    dest =*pDest;\n    if(dest==nullptr || destCap <=0){\n        destCap = srcLen * 8;\n        dest = static_cast<char*>(uprv_malloc(sizeof(char) * destCap));\n        if(dest==nullptr){\n            *status=U_MEMORY_ALLOCATION_ERROR;\n            return nullptr;\n        }\n    }\n\n    dest[0]=0;\n\n    while(srcIndex<srcLen){\n        U16_NEXT(src, srcIndex, srcLen, c);\n\n        if (U16_IS_LEAD(c) || U16_IS_TRAIL(c)) {\n            *status = U_ILLEGAL_CHAR_FOUND;\n            fprintf(stderr, \"Illegal Surrogate! \\n\");\n            uprv_free(dest);\n            return nullptr;\n        }\n\n        if((destLen+U8_LENGTH(c)) < destCap){\n\n            /* ASCII Range */\n            if(c <=0x007F){\n                switch(c) {\n                case '\\x26':\n                    uprv_strcpy(dest+( destLen),\"\\x26\\x61\\x6d\\x70\\x3b\"); /* &amp;*/\n                    destLen += static_cast<int32_t>(uprv_strlen(\"\\x26\\x61\\x6d\\x70\\x3b\"));\n                    break;\n                case '\\x3c':\n                    uprv_strcpy(dest+(destLen),\"\\x26\\x6c\\x74\\x3b\"); /* &lt;*/\n                    destLen += static_cast<int32_t>(uprv_strlen(\"\\x26\\x6c\\x74\\x3b\"));\n                    break;\n                case '\\x3e':","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/icu-small/source/tools/genrb/wrtxml.cpp#L245-L281","documentation":"While converting Unicode strings to XML-escaped UTF-8 for XLIFF output, genrb encountered an unpaired surrogate code unit. U16_NEXT extracted a value in the surrogate range (U+D800–U+DFFF) that is not part of a valid surrogate pair. XML cannot represent lone surrogates, so the conversion aborts with U_ILLEGAL_CHAR_FOUND.","triggerScenarios":"A string in the resource bundle contains a lone high surrogate (U+D800–U+DBFF) not followed by a low surrogate, or a lone low surrogate (U+DC00–U+DFFF) not preceded by a high surrogate. This passes through genrb's parser but fails during the XML output stage because XML requires well-formed UTF.","commonSituations":"String was truncated mid-surrogate-pair during editing or transfer; a supplementary character was incorrectly split across string concatenation boundaries; UTF-16 file corrupted at a surrogate boundary; resource bundle generated by tooling that doesn't properly handle supplementary characters.","solutions":["Find the string with the lone surrogate — genrb should indicate which bundle/file is being processed when this occurs","Validate the resource bundle .txt file for lone surrogates: `grep -P '[\\x{D800}-\\x{DFFF}]' <file.txt>`","Replace the lone surrogate with the correct supplementary character (use the full \\Uxxxxxxxx escape) or remove it","If the source is generated, fix the generator to emit proper UTF-16 surrogate pairs or UTF-8 directly","Use ICU's u_strToUTF8 or icu::UnicodeString to detect and repair malformed surrogates before feeding to genrb"],"exampleFix":"// before: lone surrogate in resource string\n    greeting { \"Hello \\uD800\" }\n// after: complete supplementary character or removal\n    greeting { \"Hello \\U00010000\" }","handlingStrategy":"validation","validationCode":"# Scan resource bundle files for lone surrogates before genrb\nfor f in data/*.txt; do\n    # Check for \\uD8xx-\\uDBxx not followed by \\uDCxx-\\uDFxx (lone high surrogate)\n    # and \\uDCxx-\\uDFxx not preceded by high surrogate (lone low surrogate)\n    python3 -c \"\nimport re, sys\ntext = open(sys.argv[1], encoding='utf-8').read()\n# Find all unicode escape sequences\nescapes = re.findall(r'\\\\\\\\u([0-9A-Fa-f]{4})', text)\ncodepoints = [int(e, 16) for e in escapes]\nfor i, cp in enumerate(codepoints):\n    if 0xD800 <= cp <= 0xDBFF:  # high surrogate\n        if i+1 >= len(codepoints) or not (0xDC00 <= codepoints[i+1] <= 0xDFFF):\n            print(f'Lone high surrogate at escape index {i}: U+{cp:04X}')\n    elif 0xDC00 <= cp <= 0xDFFF:  # low surrogate\n        if i == 0 or not (0xD800 <= codepoints[i-1] <= 0xDBFF):\n            print(f'Lone low surrogate at escape index {i}: U+{cp:04X}')\n\" \"$f\"\ndone","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate all Unicode escape sequences in resource bundles form proper surrogate pairs","Use \\Uxxxxxxxx escapes for supplementary characters instead of manual surrogate pairs","Ensure text editors and transfer tools preserve proper UTF encoding without splitting surrogates","Run a Unicode validation check on resource bundle files before building"],"tags":["icu","genrb","xliff","surrogate","encoding","illegal-char"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}