microsoft/edit · error

Unrecognized GCB= for U+ to U+

Error message

Unrecognized GCB={} for U+{:04X} to U+{:04X}

What it means

While extracting Grapheme_Cluster_Break values from the UCD XML, any GCB string not in the known mapping (XX/Other, CR, LF, Control, Extend, ZWJ, RI, L, V, T, LV, LVT, Prepend, SpacingMark, Extend*) hits the catch-all bail. This keeps generated tables exhaustive over the enum — unknown Unicode data is refused rather than silently mis-encoded.

Solutions

  1. Use the UCD XML version matching the generator's supported Unicode release.
  2. Add the new GCB value to the ClusterBreak enum and its mapping arm in extract_values_from_ucd, then regenerate.
  3. Verify the input file's integrity (re-download the official UCD archive) if the value looks corrupt.

Example fix

// before
_ => bail!("Unrecognized GCB={} ..."),
// after
"NewValue" => ClusterBreak::NewValue,
_ => bail!("Unrecognized GCB={} ..."),
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check GCB values in the UCD XML before generating
for node in doc.descendants().filter(|n| n.has_attribute("gcb")) {
    const KNOWN: &[&str] = &["XX","CR","LF","Control","Extend","ZWJ","RI","L","V","T","LV","LVT","Prepend","SpacingMark"];
    let v = node.attribute("gcb").unwrap();
    assert!(KNOWN.contains(&v), "unsupported GCB value {v} in UCD file");
}

Try / catch

// wrap generation and report the offending range
if let Err(e) = generate(&ucd_path) {
    let msg = e.to_string();
    if msg.starts_with("Unrecognized GCB=") {
        eprintln!("UCD version too new for this generator: {msg}");
        std::process::exit(1);
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Feeding unicode-gen a UCD XML file from a Unicode version that introduces a GCB property value the generator does not know, or a corrupted/modified GraphemeBreakProperty file with a bad gcb attribute.

Common situations: Upgrading to a newer Unicode release before updating the ClusterBreak enum; hand-edited or truncated UCD data; using the wrong UCD file (e.g. one with different attributes).

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of microsoft/edit@826b4c097b (2026-09-06). Data as JSON: /api/errors/481a928fe30baa99. Report an issue: GitHub.

Appendix: source

Thrown at crates/unicode-gen/src/main.rs:807

            let mut cb = match char_attributes.grapheme_cluster_break {
                "XX" => ClusterBreak::Other, // Anything else
                // We ignore GB3 which demands that CR × LF do not break apart, because
                // * these control characters won't normally reach our text storage
                // * otherwise we're in a raw write mode and historically conhost stores them in separate cells
                "CR" => ClusterBreak::CR,            // Carriage Return
                "LF" => ClusterBreak::LF,            // Line Feed
                "CN" => ClusterBreak::Control,       // Control
                "EX" | "SM" => ClusterBreak::Extend, // Extend, SpacingMark
                "PP" => ClusterBreak::Prepend,       // Prepend
                "ZWJ" => ClusterBreak::ZWJ,          // Zero Width Joiner
                "RI" => ClusterBreak::RI,            // Regional Indicator
                "L" => ClusterBreak::HangulL,        // Hangul Syllable Type L
                "V" => ClusterBreak::HangulV,        // Hangul Syllable Type V
                "T" => ClusterBreak::HangulT,        // Hangul Syllable Type T
                "LV" => ClusterBreak::HangulLV,      // Hangul Syllable Type LV
                "LVT" => ClusterBreak::HangulLVT,    // Hangul Syllable Type LVT
                _ => bail!(
                    "Unrecognized GCB={} for U+{:04X} to U+{:04X}",
                    char_attributes.grapheme_cluster_break,
                    range.start(),
                    range.end()
                ),
            };

            if char_attributes.extended_pictographic == "Y" {
                // Currently every single Extended_Pictographic codepoint happens to be GCB=XX.
                // This is fantastic for us because it means we can stuff it into the ClusterBreak enum
                // and treat it as an alias of EXTEND, but with the special GB11 properties.
                if cb != ClusterBreak::Other {
                    bail!(
                        "Unexpected GCB={} with ExtPict=Y for U+{:04X} to U+{:04X}",
                        char_attributes.grapheme_cluster_break,
                        range.start(),
                        range.end()
                    );

View on GitHub (pinned to 826b4c097b)