ory/hydra · error

unable to decode JSON payload into %T: %w

Error message

unable to decode JSON payload into %T: %w

What it means

After JSONScan obtains the raw text (from null, string, or []byte) it calls json.Unmarshal into the destination. This error wraps that failure, meaning the raw value is present but is not valid JSON or does not match the destination's shape (unknown fields are ignored by default, so shape/type mismatch is the usual cause).

Source

Thrown at oryx/sqlxx/types.go:504

}

// JSONScan is a generic helper for retrieving a SQL JSON-encoded value.
func JSONScan(dst, value any) error {
	// Note: raw is a string (not []byte) because the MySQL driver reuses byte slices across scans.
	// Using strings avoids the need to manually copy the byte slice.
	var raw string
	switch v := value.(type) {
	case nil:
		raw = "null"
	case string:
		raw = v
	case []byte:
		raw = string(v)
	default:
		return fmt.Errorf("unable to scan type %T as JSON into %T", value, dst)
	}
	if err := json.Unmarshal([]byte(raw), dst); err != nil {
		return fmt.Errorf("unable to decode JSON payload into %T: %w", dst, err)
	}
	return nil
}

// NullInt64 represents an int64 that may be null.
// swagger:type int64
// swagger:model nullInt64
type NullInt64 struct {
	Int   int64
	Valid bool // Valid is true if Duration is not NULL
}

// Scan implements the Scanner interface.
func (ns *NullInt64) Scan(value interface{}) error {
	d := sql.NullInt64{}
	if err := d.Scan(value); err != nil {
		return err
	}

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Print/inspect the offending raw value for the failing row and fix or migrate the stored data
  2. Validate the payload matches the destination shape (json.Valid, or unmarshal into json.RawMessage/map first)
  3. Use json.RawMessage or a flexible destination type if the column may hold heterogeneous JSON
  4. Pre-validate data on write with json.Marshal/strict unmarshal so bad data never reaches the DB

Example fix

// before
type Config struct { Host string `json:"host"` }
var c Config
// column value: `["a","b"]` -> unmarshal error
// after
type Config struct { Hosts []string `json:"hosts"` }
var c Config
if err := json.Unmarshal([]byte(raw), &c); err != nil {
    return fmt.Errorf("unable to decode JSON payload into %T: %w", dst, err)
}
Defensive patterns

Strategy: validation

Validate before calling

if !json.Valid([]byte(raw)) {
    return fmt.Errorf("invalid JSON payload: %s", raw)
}

Try / catch

var target MyType
if err := json.Unmarshal(data, &target); err != nil {
    var syn *json.SyntaxTypeError
    if errors.As(err, &syn) {
        log.Printf("bad JSON syntax at offset %d", syn.Offset)
    }
    return fmt.Errorf("unable to decode JSON payload into %T: %w", &target, err)
}

Prevention

When it happens

Trigger: json.Unmarshal fails because the column content is malformed JSON (truncated, plain text, HTML error page stored in the column) or the JSON structure does not fit the destination type (e.g. object scanned into a slice or primitive).

Common situations: Legacy rows written before a schema/type change, application code writing non-JSON strings into a JSON column, JSON arrays stored where a struct is expected, or BOM/whitespace-corrupted payloads.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/f9814ef34b97c2dd. Report an issue: GitHub.