anomalyco/sst · error

expect end of JSON object but got more token: %T: %v or err:

Error message

expect end of JSON object but got more token: %T: %v or err: %v

What it means

Once the closing '}' is consumed, UnmarshalJSON requires the decoder to be at EOF. If another token remains (or a non-EOF error exists), it reports 'expect end of JSON object but got more token'. This rejects concatenated or trailing garbage after the object.

Source

Thrown at internal/util/kv.go:62

		}
		*p = append(*p, KeyValuePair[T]{Key: key, Value: value})
	}

	// must end with a delim token '}'
	t, err = dec.Token()
	if err != nil {
		return err
	}
	if delim, ok := t.(json.Delim); !ok || delim != '}' {
		return fmt.Errorf("expect JSON object close with '}'")
	}
	if err != nil {
		return err
	}

	t, err = dec.Token()
	if err != io.EOF {
		return fmt.Errorf("expect end of JSON object but got more token: %T: %v or err: %v", t, t, err)
	}

	return nil

}
func (p KeyValuePairs[T]) MarshalJSON() ([]byte, error) {
	buf := &bytes.Buffer{}
	buf.Write([]byte{'{'})
	for i, KeyValuePair := range p {
		buf.WriteString(fmt.Sprintf("%q:", fmt.Sprintf("%v", KeyValuePair.Key)))
		encoder := json.NewEncoder(buf)
		encoder.SetEscapeHTML(false)
		err := encoder.Encode(KeyValuePair.Value)
		if err != nil {
			return nil, err
		}
		if i < len(p)-1 {
			buf.Write([]byte{','})

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Feed exactly one JSON document per Unmarshal call — split NDJSON by lines first
  2. Trim trailing whitespace/garbage from the payload
  3. Use a json.Decoder loop over multiple documents if the stream intentionally holds several objects

Example fix

// before
dec := json.NewDecoder(conn)
var kv KeyValuePairs[string]
json.Unmarshal(buf, &kv) // buf has two concatenated objects
// after
lines := bytes.Split(buf, []byte("\n"))
for _, l := range lines {
    var kv KeyValuePairs[string]
    json.Unmarshal(l, &kv)
}
Defensive patterns

Strategy: validation

Validate before calling

dec := json.NewDecoder(bytes.NewReader(raw))
if err := dec.Decode(&json.RawMessage{}); err != nil {
    return err
}
if dec.More() {
    return fmt.Errorf("trailing data after first JSON document")
}

Try / catch

var kv KeyValuePairs[string]
if err := json.Unmarshal(raw, &kv); err != nil {
    if strings.Contains(err.Error(), "expect end of JSON object") {
        return fmt.Errorf("multiple/trailing JSON documents; split NDJSON first")
    }
    return err
}

Prevention

When it happens

Trigger: Input with trailing data after the object, e.g. '{"a":1}{"b":2}' (JSON concatenation/streaming), trailing commas parsed oddly, or appended newline-separated records.

Common situations: NDJSON files fed to json.Unmarshal one blob at a time; log collectors concatenating JSON docs; copy-paste errors leaving stray characters after the object.

Related errors


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/81cdd25be310d623. Report an issue: GitHub.