d2lang/d2 · error

theme %d not found

Error message

theme %d not found

What it means

ApplyTheme validates that the requested numeric theme ID exists in the d2themes catalog. If d2themescatalog.Find returns the zero-value Theme, the ID is unknown and the graph's Theme is left unchanged, returning this error instead of applying a bogus theme.

Source

Thrown at d2graph/d2graph.go:1869

}

func (obj *Object) IsDescendantOf(ancestor *Object) bool {
	if obj == ancestor {
		return true
	}
	if obj.Parent == nil {
		return false
	}
	return obj.Parent.IsDescendantOf(ancestor)
}

// ApplyTheme applies themes on the graph level
// This is different than on the render level, which only changes colors
// A theme applied on the graph level applies special rules that change the graph
func (g *Graph) ApplyTheme(themeID int64) error {
	theme := d2themescatalog.Find(themeID)
	if theme == (d2themes.Theme{}) {
		return fmt.Errorf("theme %d not found", themeID)
	}
	g.Theme = &theme
	return nil
}

func (g *Graph) PrintString() string {
	buf := &bytes.Buffer{}
	fmt.Fprint(buf, "Objects: [")
	for _, obj := range g.Objects {
		fmt.Fprintf(buf, "%v, ", obj.AbsID())
	}
	fmt.Fprint(buf, "]")
	return buf.String()
}

func (obj *Object) IterDescendants(apply func(parent, child *Object)) {
	for _, c := range obj.ChildrenArray {
		apply(obj, c)

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Use a named constant from d2themescatalog (e.g. d2themescatalog.NeutralDefault) instead of a raw number
  2. Validate the ID against the catalog before calling ApplyTheme
  3. Update the library version if the theme exists in newer D2 releases
  4. Check user-facing config for typos in theme IDs

Example fix

// before
err := g.ApplyTheme(999)
// after
theme := d2themescatalog.Find(999)
if theme == (d2themes.Theme{}) {
	theme = d2themescatalog.NeutralDefault
}
err := g.ApplyTheme(d2themescatalog.NeutralDefault.ID)
Defensive patterns

Strategy: validation

Validate before calling

func themeExists(id int64) bool {
	return d2themescatalog.Find(id) != (d2themes.Theme{})
}
if !themeExists(themeID) { return fmt.Errorf("unsupported theme %d", themeID) }

Type guard

func isKnownTheme(t d2themes.Theme) bool { return t != (d2themes.Theme{}) }

Try / catch

if err := g.ApplyTheme(themeID); err != nil {
	log.Printf("theme %d unavailable, using default", themeID)
	err = g.ApplyTheme(d2themescatalog.NeutralDefault.ID)
}

Prevention

When it happens

Trigger: Calling (*d2graph.Graph).ApplyTheme with an int64 theme ID that is not one of the catalog's defined theme IDs (0-300+ known constants like d2themescatalog.NeutralDefault).

Common situations: Hardcoding a theme ID read from user config or a CLI flag without validating it; using a theme constant from a newer D2 version in an older vendored copy; off-by-one or typo in the numeric ID.

Related errors


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