{"record":{"id":"c970dbf835601dc1","repo":"d2lang/d2","slug":"failed-to-initialize-font-faces-v","errorCode":null,"errorMessage":"Failed to initialize font faces: %v","messagePattern":"Failed to initialize font faces: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"d2renderers/d2fonts/d2fonts_embed_wasm.go","lineNumber":125,"sourceCode":"\t\tFontEncodings.Set(Font{Family: HandDrawn, Style: FONT_STYLE_REGULAR}, str)\n\t\t// HandDrawn has no italic, so reuse regular\n\t\tFontEncodings.Set(Font{Family: HandDrawn, Style: FONT_STYLE_ITALIC}, str)\n\t}\n\n\tif str, err := compression.DecompressBrotli(fuzzyBubblesBoldBr); err != nil {\n\t\tpanic(fmt.Sprintf(\"Failed to decompress FuzzyBubbles-Bold: %v\", err))\n\t} else {\n\t\tFontEncodings.Set(Font{Family: HandDrawn, Style: FONT_STYLE_BOLD}, str)\n\t\t// HandDrawn has no semibold, so reuse bold\n\t\tFontEncodings.Set(Font{Family: HandDrawn, Style: FONT_STYLE_SEMIBOLD}, str)\n\t}\n\n\t// Trim trailing newlines\n\ttrimEncodings()\n\n\t// Initialize FontFaces with TTF files\n\tif err := initializeFontFaces(fontFacesFS); err != nil {\n\t\tpanic(fmt.Sprintf(\"Failed to initialize font faces: %v\", err))\n\t}\n}\n\n// trimEncodings removes trailing newlines from all font encodings\nfunc trimEncodings() {\n\tFontEncodings.Range(func(k Font, v string) bool {\n\t\tFontEncodings.Set(k, strings.TrimSuffix(v, \"\\n\"))\n\t\treturn true\n\t})\n}\n\n// initializeFontFaces loads TTF font files into FontFaces\nfunc initializeFontFaces(fontFacesFS embed.FS) error {\n\tFontFaces = syncmap.New[Font, []byte]()\n\n\t// SourceSansPro fonts\n\tfontFiles := []struct {\n\t\tfile   string","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2renderers/d2fonts/d2fonts_embed_wasm.go#L107-L143","documentation":"At the end of WASM init, d2fonts calls initializeFontFaces(fontFacesFS) which loads the embedded TTF files into OpenType font faces. Any error (missing TTF in the embedded FS, unparsable font data, corrupt asset) is escalated to a panic with this message. It means the embedded font-face filesystem or TTF contents are invalid.","triggerScenarios":"Process start of a WASM build: init at d2renderers/d2fonts/d2fonts_embed_wasm.go:125 calls initializeFontFaces(fontFacesFS) which returns an error — typically a TTF missing from the embed.FS or failing OpenType parsing.","commonSituations":"Missing font TTFs from the embedded FS after a bad build; TTF assets replaced with wrong/corrupt files; partial checkout or submodule mismatch; custom forks adding fonts with unsupported formats (e.g. OTF/WOFF instead of TTF).","solutions":["Rebuild from a clean checkout so all TTFs are embedded in fontFacesFS","Verify every TTF referenced by initializeFontFaces exists in the embedded filesystem","Validate each embedded TTF parses with opentype.Parse/ParseCollection and replace bad files","If adding custom fonts, confirm they are genuine TTF (TrueType glyf) files, not OTF/WOFF"],"exampleFix":"// before (fontFacesFS missing a ttf)\n//go:embed fonts/*.ttf  // file SourceCodePro-Regular.ttf absent\n// after\ncp fonts/SourceCodePro-Regular.ttf d2renderers/d2fonts/fonts/ && go build","handlingStrategy":"validation","validationCode":"// Verify all TTFs referenced by initializeFontFaces exist and parse before building\nfor _, f := range requiredFontTTFs {\n    data, err := fontFacesFS.ReadFile(f)\n    if err != nil { panic(\"missing font: \" + f) }\n    if _, err := opentype.ParseCollection(data); err != nil { panic(\"bad ttf: \" + f) }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add a unit test that opens every file in fontFacesFS and parses it as TTF","Only embed genuine .ttf (TrueType) files; reject OTF/WOFF","Rebuild cleanly after any change to the fonts directory"],"tags":["go","panic","init","wasm","fonts","embedded-assets"],"backgroundTag":"embedded-font-init-failed","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}