d2lang/d2 · critical
Failed to initialize font faces: %v
Error message
Failed to initialize font faces: %v
What it means
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.
Source
Thrown at d2renderers/d2fonts/d2fonts_embed_wasm.go:125
FontEncodings.Set(Font{Family: HandDrawn, Style: FONT_STYLE_REGULAR}, str)
// HandDrawn has no italic, so reuse regular
FontEncodings.Set(Font{Family: HandDrawn, Style: FONT_STYLE_ITALIC}, str)
}
if str, err := compression.DecompressBrotli(fuzzyBubblesBoldBr); err != nil {
panic(fmt.Sprintf("Failed to decompress FuzzyBubbles-Bold: %v", err))
} else {
FontEncodings.Set(Font{Family: HandDrawn, Style: FONT_STYLE_BOLD}, str)
// HandDrawn has no semibold, so reuse bold
FontEncodings.Set(Font{Family: HandDrawn, Style: FONT_STYLE_SEMIBOLD}, str)
}
// Trim trailing newlines
trimEncodings()
// Initialize FontFaces with TTF files
if err := initializeFontFaces(fontFacesFS); err != nil {
panic(fmt.Sprintf("Failed to initialize font faces: %v", err))
}
}
// trimEncodings removes trailing newlines from all font encodings
func trimEncodings() {
FontEncodings.Range(func(k Font, v string) bool {
FontEncodings.Set(k, strings.TrimSuffix(v, "\n"))
return true
})
}
// initializeFontFaces loads TTF font files into FontFaces
func initializeFontFaces(fontFacesFS embed.FS) error {
FontFaces = syncmap.New[Font, []byte]()
// SourceSansPro fonts
fontFiles := []struct {
file stringView on GitHub (pinned to 0d69dca6f5)
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
Example fix
// before (fontFacesFS missing a ttf) //go:embed fonts/*.ttf // file SourceCodePro-Regular.ttf absent // after cp fonts/SourceCodePro-Regular.ttf d2renderers/d2fonts/fonts/ && go build
Defensive patterns
Strategy: validation
Validate before calling
// Verify all TTFs referenced by initializeFontFaces exist and parse before building
for _, f := range requiredFontTTFs {
data, err := fontFacesFS.ReadFile(f)
if err != nil { panic("missing font: " + f) }
if _, err := opentype.ParseCollection(data); err != nil { panic("bad ttf: " + f) }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- Failed to decompress SourceCodePro-Italic: %v
- Failed to decompress FuzzyBubbles-Regular: %v
- Failed to decompress FuzzyBubbles-Bold: %v
- Failed to decompress paper texture: %v
- create OpenType face: %v
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/c970dbf835601dc1.
Report an issue: GitHub.