wailsapp/wails · error
CreateFontIndirect failed
Error message
CreateFontIndirect failed
What it means
After validating the style, NewFont measures screen DPI, builds a LOGFONT (height = -MulDiv(pointSize, dpi, 72), weight/family/italic from style) and calls CreateFontIndirect via createForDPI; it panics when the returned HFONT is NULL. CreateFontIndirect fails only under GDI handle exhaustion or with a malformed LOGFONT; any family string is accepted (Windows performs font substitution), so the family name itself is not the trigger.
Source
Thrown at v2/internal/frontend/desktop/windows/winc/font.go:52
func NewFont(family string, pointSize int, style byte) *Font {
if style > FontBold|FontItalic|FontUnderline|FontStrikeOut {
panic("Invalid font style")
}
//Retrive screen DPI
hDC := w32.GetDC(0)
defer w32.ReleaseDC(0, hDC)
screenDPIY := w32.GetDeviceCaps(hDC, w32.LOGPIXELSY)
font := Font{
family: family,
pointSize: pointSize,
style: style,
}
font.hfont = font.createForDPI(screenDPIY)
if font.hfont == 0 {
panic("CreateFontIndirect failed")
}
return &font
}
func (fnt *Font) createForDPI(dpi int) w32.HFONT {
var lf w32.LOGFONT
lf.Height = int32(-w32.MulDiv(fnt.pointSize, dpi, 72))
if fnt.style&FontBold > 0 {
lf.Weight = w32.FW_BOLD
} else {
lf.Weight = w32.FW_NORMAL
}
if fnt.style&FontItalic > 0 {
lf.Italic = 1
}
if fnt.style&FontUnderline > 0 {View on GitHub (pinned to 0e754b1b40)
Solutions
- Cache fonts: create them once (package-level or per-window) and reuse across controls
- Delete HFONTs of replaced fonts with w32.DeleteObject when a control's font is swapped
- Watch GDI object count in Task Manager to confirm exhaustion; find the true leak with GDIView
Example fix
// before
for _, row := range rows {
row.SetFont(winc.NewFont("MS Shell Dlg 2", 8, 0)) // new HFONT per row -> exhaustion -> panic
}
// after
var uiFont = winc.NewFont("MS Shell Dlg 2", 8, 0) // once
for _, row := range rows {
row.SetFont(uiFont)
} Defensive patterns
Strategy: validation
Validate before calling
// Cache fonts; only create when the GDI budget allows.
var fontCache = map[fontKey]*winc.Font{}
type fontKey struct { fam string; size int; style byte }
func getFont(fam string, size int, style byte) *winc.Font {
k := fontKey{fam, size, style}
if f, ok := fontCache[k]; ok { return f }
f := winc.NewFont(fam, size, style)
fontCache[k] = f
return f
} Prevention
- One Font instance per distinct style, created once
- Delete replaced HFONTs with w32.DeleteObject
- Monitor GDI objects during development
When it happens
Trigger: Creating Font objects per-control/per-repaint and never deleting the HFONTs until the 10000 GDI handle quota is reached; creating fonts during shutdown while GDI is unavailable.
Common situations: Apps applying fonts in loops (e.g. styling every list item with a fresh NewFont); the DefaultFont-style package var pattern broken by per-call creation; GDI leak elsewhere in the process.
Related errors
- Faild to create solid color brush
- Failed to create null brush
- Create canvas from %v failed.
- Invalid font style
- GetSysColorBrush failed
AI-assisted analysis of wailsapp/wails@0e754b1b40 (2026-08-15).
Data as JSON: /api/errors/b784956ce5e560b0.
Report an issue: GitHub.