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   string

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Rebuild from a clean checkout so all TTFs are embedded in fontFacesFS
  2. Verify every TTF referenced by initializeFontFaces exists in the embedded filesystem
  3. Validate each embedded TTF parses with opentype.Parse/ParseCollection and replace bad files
  4. 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

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


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/c970dbf835601dc1. Report an issue: GitHub.