nodejs/node · error

U_ILLEGAL_CHAR_FOUND

U_ILLEGAL_CHAR_FOUND

Error message

Illegal Surrogate! 

What it means

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.

Source

Thrown at deps/icu-small/source/tools/genrb/wrtxml.cpp:263

    }
    dest =*pDest;
    if(dest==nullptr || destCap <=0){
        destCap = srcLen * 8;
        dest = static_cast<char*>(uprv_malloc(sizeof(char) * destCap));
        if(dest==nullptr){
            *status=U_MEMORY_ALLOCATION_ERROR;
            return nullptr;
        }
    }

    dest[0]=0;

    while(srcIndex<srcLen){
        U16_NEXT(src, srcIndex, srcLen, c);

        if (U16_IS_LEAD(c) || U16_IS_TRAIL(c)) {
            *status = U_ILLEGAL_CHAR_FOUND;
            fprintf(stderr, "Illegal Surrogate! \n");
            uprv_free(dest);
            return nullptr;
        }

        if((destLen+U8_LENGTH(c)) < destCap){

            /* ASCII Range */
            if(c <=0x007F){
                switch(c) {
                case '\x26':
                    uprv_strcpy(dest+( destLen),"\x26\x61\x6d\x70\x3b"); /* &amp;*/
                    destLen += static_cast<int32_t>(uprv_strlen("\x26\x61\x6d\x70\x3b"));
                    break;
                case '\x3c':
                    uprv_strcpy(dest+(destLen),"\x26\x6c\x74\x3b"); /* &lt;*/
                    destLen += static_cast<int32_t>(uprv_strlen("\x26\x6c\x74\x3b"));
                    break;
                case '\x3e':

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Find the string with the lone surrogate — genrb should indicate which bundle/file is being processed when this occurs
  2. Validate the resource bundle .txt file for lone surrogates: `grep -P '[\x{D800}-\x{DFFF}]' <file.txt>`
  3. Replace the lone surrogate with the correct supplementary character (use the full \Uxxxxxxxx escape) or remove it
  4. If the source is generated, fix the generator to emit proper UTF-16 surrogate pairs or UTF-8 directly
  5. Use ICU's u_strToUTF8 or icu::UnicodeString to detect and repair malformed surrogates before feeding to genrb

Example fix

// before: lone surrogate in resource string
    greeting { "Hello \uD800" }
// after: complete supplementary character or removal
    greeting { "Hello \U00010000" }
Defensive patterns

Strategy: validation

Validate before calling

# Scan resource bundle files for lone surrogates before genrb
for f in data/*.txt; do
    # Check for \uD8xx-\uDBxx not followed by \uDCxx-\uDFxx (lone high surrogate)
    # and \uDCxx-\uDFxx not preceded by high surrogate (lone low surrogate)
    python3 -c "
import re, sys
text = open(sys.argv[1], encoding='utf-8').read()
# Find all unicode escape sequences
escapes = re.findall(r'\\\\u([0-9A-Fa-f]{4})', text)
codepoints = [int(e, 16) for e in escapes]
for i, cp in enumerate(codepoints):
    if 0xD800 <= cp <= 0xDBFF:  # high surrogate
        if i+1 >= len(codepoints) or not (0xDC00 <= codepoints[i+1] <= 0xDFFF):
            print(f'Lone high surrogate at escape index {i}: U+{cp:04X}')
    elif 0xDC00 <= cp <= 0xDFFF:  # low surrogate
        if i == 0 or not (0xD800 <= codepoints[i-1] <= 0xDBFF):
            print(f'Lone low surrogate at escape index {i}: U+{cp:04X}')
" "$f"
done

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/2dba660d0554dd2e. Report an issue: GitHub.