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")) {
					continue

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Validate the JSON with json.Valid(b) before hashing
  2. Re-serialize the diagram from the compiled d2target.Diagram instead of hashing hand-modified bytes
  3. 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

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


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