{"record":{"id":"1b5384f841022865","repo":"d2lang/d2","slug":"theme-d-not-found","errorCode":null,"errorMessage":"theme %d not found","messagePattern":"theme (.+?) not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2graph/d2graph.go","lineNumber":1869,"sourceCode":"}\n\nfunc (obj *Object) IsDescendantOf(ancestor *Object) bool {\n\tif obj == ancestor {\n\t\treturn true\n\t}\n\tif obj.Parent == nil {\n\t\treturn false\n\t}\n\treturn obj.Parent.IsDescendantOf(ancestor)\n}\n\n// ApplyTheme applies themes on the graph level\n// This is different than on the render level, which only changes colors\n// A theme applied on the graph level applies special rules that change the graph\nfunc (g *Graph) ApplyTheme(themeID int64) error {\n\ttheme := d2themescatalog.Find(themeID)\n\tif theme == (d2themes.Theme{}) {\n\t\treturn fmt.Errorf(\"theme %d not found\", themeID)\n\t}\n\tg.Theme = &theme\n\treturn nil\n}\n\nfunc (g *Graph) PrintString() string {\n\tbuf := &bytes.Buffer{}\n\tfmt.Fprint(buf, \"Objects: [\")\n\tfor _, obj := range g.Objects {\n\t\tfmt.Fprintf(buf, \"%v, \", obj.AbsID())\n\t}\n\tfmt.Fprint(buf, \"]\")\n\treturn buf.String()\n}\n\nfunc (obj *Object) IterDescendants(apply func(parent, child *Object)) {\n\tfor _, c := range obj.ChildrenArray {\n\t\tapply(obj, c)","sourceCodeStart":1851,"sourceCodeEnd":1887,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2graph/d2graph.go#L1851-L1887","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Use a named constant from d2themescatalog (e.g. d2themescatalog.NeutralDefault) instead of a raw number","Validate the ID against the catalog before calling ApplyTheme","Update the library version if the theme exists in newer D2 releases","Check user-facing config for typos in theme IDs"],"exampleFix":"// before\nerr := g.ApplyTheme(999)\n// after\ntheme := d2themescatalog.Find(999)\nif theme == (d2themes.Theme{}) {\n\ttheme = d2themescatalog.NeutralDefault\n}\nerr := g.ApplyTheme(d2themescatalog.NeutralDefault.ID)","handlingStrategy":"validation","validationCode":"func themeExists(id int64) bool {\n\treturn d2themescatalog.Find(id) != (d2themes.Theme{})\n}\nif !themeExists(themeID) { return fmt.Errorf(\"unsupported theme %d\", themeID) }","typeGuard":"func isKnownTheme(t d2themes.Theme) bool { return t != (d2themes.Theme{}) }","tryCatchPattern":"if err := g.ApplyTheme(themeID); err != nil {\n\tlog.Printf(\"theme %d unavailable, using default\", themeID)\n\terr = g.ApplyTheme(d2themescatalog.NeutralDefault.ID)\n}","preventionTips":["Use d2themescatalog named constants instead of raw IDs","Validate user-supplied theme IDs against the catalog before applying","Pin library versions when relying on newly added theme IDs"],"tags":["d2","theme","configuration","invalid-input"],"backgroundTag":"invalid-theme-id","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}