anomalyco/sst · error

JSON value can't be decoded: %T: %v

Error message

JSON value can't be decoded: %T: %v

What it means

After reading each key, UnmarshalJSON decodes the value into T; if the value does not match T (or is malformed) it wraps the failure as 'JSON value can't be decoded: <type>: <value>'. It tells you which key's value failed to fit the declared generic type.

Source

Thrown at internal/util/kv.go:43

	}
	if delim, ok := t.(json.Delim); !ok || delim != '{' {
		return fmt.Errorf("expect JSON object open with '{'")
	}

	for dec.More() {
		t, err = dec.Token()
		if err != nil {
			return err
		}

		key, ok := t.(string)
		if !ok {
			return fmt.Errorf("expecting JSON key should be always a string: %T: %v", t, t)
		}
		var value T
		err = dec.Decode(&value)
		if err != nil {
			return fmt.Errorf("JSON value can't be decoded: %T: %v", value, value)
		}
		*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 {

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Change T to match the actual value type (e.g. KeyValuePairs[string] or KeyValuePairs[any])
  2. Fix the producer to emit values of type T
  3. Use json.Number/any as T and convert manually after decode

Example fix

// before
var kv KeyValuePairs[int]
json.Unmarshal([]byte(`{"port":"8080"}`), &kv)
// after
var kv KeyValuePairs[string]
json.Unmarshal([]byte(`{"port":"8080"}`), &kv)
port, _ := strconv.Atoi(kv[0].Value)
Defensive patterns

Strategy: type-guard

Validate before calling

var probe map[string]any
if err := json.Unmarshal(raw, &probe); err != nil {
    return err
}
for k, v := range probe {
    if _, ok := v.(string); !ok {
        return fmt.Errorf("key %q value is %T, want string", k, v)
    }
}

Type guard

func allValuesOfType[T any](raw []byte) bool {
    var probe map[string]T
    return json.Unmarshal(raw, &probe) == nil
}

Try / catch

var kv KeyValuePairs[string]
if err := json.Unmarshal(raw, &kv); err != nil {
    if strings.Contains(err.Error(), "can't be decoded") {
        return fmt.Errorf("value type mismatch; use a looser T like any or json.Number")
    }
    return err
}

Prevention

When it happens

Trigger: Decoding an object whose values are, say, strings into KeyValuePairs[int] (e.g. {"port": "8080"} into int), or a value being null/nested where T is a scalar.

Common situations: Environment/config files where values are quoted strings but the Go type expects numbers; schema drift where an API started returning objects instead of scalars; a null sneaking into a field typed as non-pointer T.

Related errors


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