{"record":{"id":"8504b5d667ce1987","repo":"zed-industries/zed","slug":"native-font-id-space-exhausted","errorCode":null,"errorMessage":"native font ID space exhausted","messagePattern":"native font ID space exhausted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui_web/src/text_system.rs","lineNumber":267,"sourceCode":"impl PlatformTextSystem for WebTextSystem {\n    fn set_missing_glyph_sink(&self, sink: Option<Arc<dyn MissingGlyphSink>>) {\n        // Cosmic must not report missing glyphs before Canvas has a chance to replace them.\n        self.state.write().missing_glyph_sink = sink;\n    }\n\n    fn add_fonts(&self, fonts: Vec<Cow<'static, [u8]>>) -> Result<()> {\n        self.native.add_fonts(fonts)?;\n        self.state.write().measurements.clear();\n        Ok(())\n    }\n\n    fn all_font_names(&self) -> Vec<String> {\n        self.native.all_font_names()\n    }\n\n    fn font_id(&self, font: &Font) -> Result<FontId> {\n        let font_id = self.native.font_id(font)?;\n        ensure!(\n            font_id.0 & CANVAS_FONT_BIT == 0,\n            \"native font ID space exhausted\"\n        );\n        let mut descriptor = font.clone();\n        (descriptor.weight, descriptor.style) = self.native.font_weight_and_style(font_id)?;\n        self.state\n            .write()\n            .descriptors\n            .entry(font_id)\n            .or_insert(descriptor);\n        Ok(font_id)\n    }\n\n    fn prewarm_fonts(&self, font_ids: &[FontId]) {\n        if font_ids\n            .iter()\n            .all(|font_id| font_id.0 & CANVAS_FONT_BIT == 0)\n        {","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/zed-industries/zed/blob/916fc2b8cb3a815cbef4a3b40e13081be72036b6/crates/gpui_web/src/text_system.rs#L249-L285","documentation":"When resolving a Font descriptor, the web text system delegates to the native font provider and then tags the resulting FontId with CANVAS_FONT_BIT only for Canvas fallback fonts. To keep the two ID spaces disjoint, it asserts the native provider never returns an ID with the CANVAS_FONT_BIT already set. If it does, the native font ID space is considered exhausted/corrupted and this error is thrown.","triggerScenarios":"Calling font_id(&Font) when self.native.font_id(font) returns a FontId whose high bit (CANVAS_FONT_BIT, 1 << (usize::BITS - 1)) is set — i.e. the native provider has handed out an ID colliding with the Canvas half of the space, or a stale/corrupted FontId was fed back through the resolution path.","commonSituations":"A FontId from a Canvas fallback font being passed back into font_id() as if it were a native font (mixing up ID origins after caching), or a native backend bug/wraparound after an enormous number of font loads. Ordinary font-family resolution will not hit this.","solutions":["Confirm the FontId passed to font_id originated from the native provider, not from a Canvas fallback font (which has CANVAS_FONT_BIT set)","Check font caching so Canvas-tagged IDs are never routed back through native.font_id()","Inspect the native font provider for ID reuse/wraparound bugs; log the offending font_id.0 value to confirm bit corruption","If seen on a 32-bit or custom target, review the CANVAS_FONT_BIT split which leaves only half the space for native IDs"],"exampleFix":"// before\nlet font_id = self.native.font_id(font)?;\nensure!(\n    font_id.0 & CANVAS_FONT_BIT == 0,\n    \"native font ID space exhausted\"\n);\n// after\nlet font_id = self.native.font_id(font)?;\nensure!(\n    font_id.0 & CANVAS_FONT_BIT == 0,\n    \"native font ID space exhausted (id={:x})\",\n    font_id.0\n); // offending id indicates a stale Canvas-tagged FontId was passed in","handlingStrategy":"type-guard","validationCode":"fn safe_font_id(id: FontId) -> Option<FontId> {\n    (id.0 & CANVAS_FONT_BIT == 0).then_some(id)\n}\n// only pass safe_font_id results back into native font resolution","typeGuard":"fn is_native_font_id(id: FontId) -> bool {\n    id.0 & CANVAS_FONT_BIT == 0\n}","tryCatchPattern":"match text_system.font_id(&font) {\n    Ok(id) => id,\n    Err(err) if err.to_string().contains(\"native font ID space\") => {\n        // the FontId routed here was Canvas-tagged or corrupted; re-resolve from the descriptor\n        re_resolve_font(&font)?\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Keep FontId provenance explicit: never feed a Canvas fallback FontId back into font_id()","Store Font objects (descriptors), not raw FontIds, in long-lived app state","Treat FontId as opaque; never serialize or persist it","If implementing a custom native provider, ensure issued IDs never set the top bit"],"tags":["fonts","id-space","wasm","resource-exhaustion"],"backgroundTag":"value-out-of-range","analyzedSha":"916fc2b8cb3a815cbef4a3b40e13081be72036b6","analyzedAt":"2026-09-19T19:09:50.599Z","contentChangedAt":"2026-09-19T19:09:50.599Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}