d2lang/d2 · error
invalid luminance category
Error message
invalid luminance category
What it means
blendMode maps a luminance category string ("bright", "normal", "dark", "darker") to an SVG mix-blend-mode used by sketch-style overlay themes. The categories come from theme color fields; if a luminance value outside the four known categories reaches this function, it panics. It is an internal invariant protecting against malformed themes.
Source
Thrown at d2renderers/d2svg/d2svg.go:3394
out += ".light-code{display: block}"
out += ".dark-code{display: none}"
}
return out, nil
}
func blendMode(lc string) string {
switch lc {
case "bright":
return "darken"
case "normal":
return "color-burn"
case "dark":
return "overlay"
case "darker":
return "lighten"
}
panic("invalid luminance category")
}
type DiagramObject interface {
GetID() string
GetZIndex() int
}
// sortObjects sorts all diagrams objects (shapes and connections) in the desired drawing order
// the sorting criteria is:
// 1. zIndex, lower comes first
// 2. two shapes with the same zIndex are sorted by their level (container nesting), containers come first
// 3. two shapes with the same zIndex and same level, are sorted in the order they were exported
// 4. shape and edge, shapes come first
func sortObjects(allObjects []DiagramObject) {
sort.SliceStable(allObjects, func(i, j int) bool {
// first sort by zIndex
iZIndex := allObjects[i].GetZIndex()
jZIndex := allObjects[j].GetZIndex()View on GitHub (pinned to 0d69dca6f5)
Solutions
- Fix the custom theme's color values so the computed luminance falls into a supported category
- Only use known luminance category values when constructing themes programmatically
- Patch blendMode to handle the new category if you intentionally introduced one
- Test custom themes through d2svg Render before shipping; fall back to the default theme if rendering panics
Example fix
// before theme.Color.N7 = "#12345678" // 8-digit hex yields unknown luminance // after theme.Color.N7 = "#123456" // standard hex in supported range
Defensive patterns
Strategy: validation
Validate before calling
// Validate custom theme colors produce a supported luminance category before Render
cat := luminanceToCategory(theme.Color.N7)
switch cat {
case "bright", "normal", "dark", "darker":
default:
return fmt.Errorf("theme color %q yields invalid luminance category %q", theme.Color.N7, cat)
} Type guard
func validLuminanceCategory(lc string) bool {
switch lc {
case "bright", "normal", "dark", "darker":
return true
}
return false
} Try / catch
// Recover around Render when using custom themes
defer func() {
if r := recover(); r != nil {
if s, ok := r.(string); ok && s == "invalid luminance category" {
err = fmt.Errorf("theme has invalid luminance category")
} else { panic(r) }
}
}() Prevention
- Derive custom themes from the default theme rather than inventing color fields
- Use standard 6/8-digit sRGB hex colors in themes
- Test any custom theme through d2svg Render before release
- Update blendMode when introducing new luminance categories
When it happens
Trigger: Rendering with an inline/custom theme whose color luminance category (derived from theme color fields like N7 via luminance helpers) is not one of "bright"/"normal"/"dark"/"darker" when d2svg applies sketch streak overlays.
Common situations: Hand-written custom theme JSON with colors yielding an unexpected luminance bucket; theme fields set to arbitrary strings in programmatic theme construction; theme version drift where a new category was added but blendMode not updated.
Related errors
- received empty arrow head marker for: %#v
- unknown svg path command "%s"
- Failed to decompress SourceCodePro-Italic: %v
- Failed to decompress FuzzyBubbles-Regular: %v
- Failed to decompress FuzzyBubbles-Bold: %v
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/b26e4647f5c8d53c.
Report an issue: GitHub.