d2lang/d2 · error
decode diagram hash JSON: object key has type %T
Error message
decode diagram hash JSON: object key has type %T
What it means
Stable diagram hashing walks the diagram JSON manually so the icon URL field can be canonicalized before hashing. While walking an object, each JSON key must be a string; if the decoder token is not a string, this error is returned. This only happens on malformed JSON, since encoding/json normally guarantees string keys in objects.
Source
Thrown at d2target/d2target.go:266
token, err := dec.Token()
if err != nil {
return err
}
delim, ok := token.(json.Delim)
if !ok {
return nil
}
switch delim {
case '{':
for dec.More() {
keyToken, err := dec.Token()
if err != nil {
return err
}
key, ok := keyToken.(string)
if !ok {
return fmt.Errorf("decode diagram hash JSON: object key has type %T", keyToken)
}
if key != "icon" {
if err := walkValue(); err != nil {
return err
}
continue
}
valueStart, err := hashJSONValueStart(b, int(dec.InputOffset()))
if err != nil {
return err
}
var raw json.RawMessage
if err := dec.Decode(&raw); err != nil {
return fmt.Errorf("decode icon URL for stable diagram hash: %w", err)
}
if bytes.Equal(raw, []byte("null")) {
continueView on GitHub (pinned to 0d69dca6f5)
Solutions
- Validate the JSON with json.Valid(b) before hashing
- Re-serialize the diagram from the compiled d2target.Diagram instead of hashing hand-modified bytes
- Ensure no concurrent writers are mutating the JSON buffer while hashing
Example fix
// before
stable, err := StableHash(corruptBytes)
// after
if !json.Valid(b) { return errors.New("invalid diagram json") }
stable, err := StableHash(b) Defensive patterns
Strategy: validation
Validate before calling
if !json.Valid(b) {
return errors.New("diagram JSON is malformed")
} Try / catch
out, err := StableHashWithIcons(b)
if err != nil && strings.Contains(err.Error(), "decode diagram hash JSON") {
// regenerate diagram JSON and retry
} Prevention
- Always validate JSON before hashing
- Re-serialize diagrams instead of caching mutated bytes
- Avoid concurrent writes to buffers being hashed
When it happens
Trigger: Calling the stable-hash function (used by d2 for deterministic diagram hashes) on JSON that is corrupt, truncated mid-token, or produced by a non-standard encoder that emits non-string object keys.
Common situations: Patching diagram JSON with low-level tools before hashing; passing non-JSON bytes to the hasher; concurrency corruption of a shared byte buffer.
Related errors
- failed to unmarshal input to graph: %s
- failed to unmarshal input graph to graph: %s
- decode icon URL for stable diagram hash: %w
- decode icon URL for stable diagram hash: invalid offsets %d:
- decode diagram hash JSON: got closing token %v, want }
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/d09df026207b7c92.
Report an issue: GitHub.