d2lang/d2 · error

decode diagram hash JSON: unexpected delimiter %q

Error message

decode diagram hash JSON: unexpected delimiter %q

What it means

The stable-hash walker only expects '{', '[', or end-of-value tokens while descending. Any other delimiter token in the JSON stream hits the default branch and returns this error, naming the unexpected delimiter. It indicates the input is not structured as expected for canonicalization.

Source

Thrown at d2target/d2target.go:320

			}
			if closeToken != json.Delim('}') {
				return fmt.Errorf("decode diagram hash JSON: got closing token %v, want }", closeToken)
			}
		case '[':
			for dec.More() {
				if err := walkValue(); err != nil {
					return err
				}
			}
			closeToken, err := dec.Token()
			if err != nil {
				return err
			}
			if closeToken != json.Delim(']') {
				return fmt.Errorf("decode diagram hash JSON: got closing token %v, want ]", closeToken)
			}
		default:
			return fmt.Errorf("decode diagram hash JSON: unexpected delimiter %q", delim)
		}
		return nil
	}

	if err := walkValue(); err != nil {
		return nil, err
	}
	out.Write(b[lastWrite:])
	return out.Bytes(), nil
}

func hashJSONValueStart(b []byte, keyEnd int) (int, error) {
	i := keyEnd
	for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\r' || b[i] == '\n') {
		i++
	}
	if i < len(b) && b[i] == ':' {
		i++

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Verify the input is valid JSON with json.Valid before calling the hash function
  2. Re-generate the diagram JSON via d2graph/d2target serialization
  3. Check the entry point: hash the serialized diagram, not the DSL source

Example fix

// before
out, _ := StableHashWithIcons([]byte(dslSource)) // not JSON
// after
b, _ := json.Marshal(diagram)
out, _ := StableHashWithIcons(b)
Defensive patterns

Strategy: validation

Validate before calling

if !json.Valid(b) {
	return errors.New("input to stable hash must be valid JSON")
}

Prevention

When it happens

Trigger: Stable-hashing JSON that starts or contains a stray delimiter (e.g. a bare '}' or a token sequence the walker didn't anticipate), typically from non-JSON or corrupt input.

Common situations: Passing non-JSON data (YAML, raw text) to the hash function; corrupted cached diagram bytes; buggy custom JSON producers.

Related errors


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