{"record":{"id":"1940eb78807189ff","repo":"microsoft/edit","slug":"unexpected-gcb-with-incb-for-u-04x-to-u","errorCode":null,"errorMessage":"Unexpected GCB={} with InCB={} for U+{:04X} to U+{:04X}","messagePattern":"Unexpected GCB=(.+?) with InCB=(.+?) for U\\+(.+?) to U\\+(.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/unicode-gen/src/main.rs","lineNumber":836,"sourceCode":"                // and treat it as an alias of EXTEND, but with the special GB11 properties.\n                if cb != ClusterBreak::Other {\n                    bail!(\n                        \"Unexpected GCB={} with ExtPict=Y for U+{:04X} to U+{:04X}\",\n                        char_attributes.grapheme_cluster_break,\n                        range.start(),\n                        range.end()\n                    );\n                }\n\n                cb = ClusterBreak::ExtPic;\n            }\n\n            if !matches!(char_attributes.indic_conjunct_break, \"None\" | \"Extend\") {\n                // If it's not None/Extend, it's Linker/Consonant, and currently\n                // all of them are GCB=EX/XX. Since we treat them almost like extenders,\n                // we need to revisit our assumptions if this ever changes.\n                if !matches!(cb, ClusterBreak::Other | ClusterBreak::Extend) {\n                    bail!(\n                        \"Unexpected GCB={} with InCB={} for U+{:04X} to U+{:04X}\",\n                        char_attributes.grapheme_cluster_break,\n                        char_attributes.indic_conjunct_break,\n                        range.start(),\n                        range.end()\n                    );\n                }\n                cb = match char_attributes.indic_conjunct_break {\n                    \"Linker\" => ClusterBreak::InCBLinker,\n                    \"Consonant\" => ClusterBreak::InCBConsonant,\n                    _ => bail!(\n                        \"Unrecognized InCB={} for U+{:04X} to U+{:04X}\",\n                        char_attributes.indic_conjunct_break,\n                        range.start(),\n                        range.end()\n                    ),\n                };\n            }","sourceCodeStart":818,"sourceCodeEnd":854,"githubUrl":"https://github.com/microsoft/edit/blob/826b4c097b6f14ba0a846dc56f2f0223a3aaf73a/crates/unicode-gen/src/main.rs#L818-L854","documentation":"Indic_Conjunct_Break (InCB) values other than None/Extend are Linker/Consonant, which the generator assumes always co-occur with GCB=EX/XX (Extend or Other). If an InCB Linker/Consonant range has any other GCB, the assumption behind treating them like extenders fails and it bails.","triggerScenarios":"A UCD release where a Linker/Consonant codepoint carries a GCB value other than Extend or Other; or mismatched UCD files where IndicConjunctBreak and GraphemeBreakProperty data come from different versions.","commonSituations":"Updating to a newer Unicode version (InCB was introduced in Unicode 15.1) without re-validating the assumptions; mixing GraphemeBreakProperty and IndicConjunctBreak files from different releases.","solutions":["Regenerate using a consistent UCD file set from the supported Unicode version.","If a new release legitimately changes the co-occurrence, widen the matches! guard and update the extender modeling for InCB.","Re-check the source UCD file if the combination looks like data corruption."],"exampleFix":"// before\nif !matches!(cb, ClusterBreak::Other | ClusterBreak::Extend) { bail!(\"Unexpected GCB=... with InCB=...\") }\n// after\n// allow newly observed GCB for InCB Linker/Consonant\nif !matches!(cb, ClusterBreak::Other | ClusterBreak::Extend | ClusterBreak::SpacingMark) { bail!(...) }","handlingStrategy":"try-catch","validationCode":"// ensure GraphemeBreakProperty and IndicConjunctBreak come from the same release\nassert_eq!(ucd_version(\"GraphemeBreakProperty.xml\"), ucd_version(\"IndicConjunctBreak.xml\"));","typeGuard":null,"tryCatchPattern":"match generate(&ucd_path) {\n    Err(e) if e.to_string().contains(\"with InCB=\") => {\n        eprintln!(\"InCB/GCB invariant broken — check Unicode version consistency: {e}\");\n        std::process::exit(1);\n    }\n    r => r?,\n}","preventionTips":["Regenerate InCB-aware tables only with the UCD release the generator was written for (Unicode 15.1+).","Diff new InCB vs GCB co-occurrences before committing regenerated tables.","Update the matches! guard deliberately when the Unicode spec changes, not silently."],"tags":["unicode","invariant","indic-conjunct-break"],"backgroundTag":"internal-invariant-violation","analyzedSha":"826b4c097b6f14ba0a846dc56f2f0223a3aaf73a","analyzedAt":"2026-09-06T13:30:05.543Z","contentChangedAt":"2026-09-06T13:30:05.543Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}