ory/hydra · error

cannot scan %T into JSONRawMessage

Error message

cannot scan %T into JSONRawMessage

What it means

JSONRawMessage.Scan supports copying from []byte, string, and nil database values. Any other Go type returned by the driver (e.g. float64 from some drivers, time.Time, or a nested value) has no conversion defined, so Scan returns this error naming the unsupported type %T. It is a type-contract failure between the driver and this Valuer/Scanner type.

Source

Thrown at oryx/sqlxx/types.go:396

	}

	return string(m), nil
}

// JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger.
type JSONRawMessage json.RawMessage

// Scan implements the Scanner interface.
func (m *JSONRawMessage) Scan(value interface{}) error {
	switch v := value.(type) {
	case []byte:
		*m = slices.Clone(v)
	case string:
		*m = JSONRawMessage(v)
	case nil:
		*m = JSONRawMessage("null")
	default:
		return errors.Errorf("cannot scan %T into JSONRawMessage", value)
	}
	return nil
}

// Value implements the driver Valuer interface.
func (m JSONRawMessage) Value() (driver.Value, error) {
	if len(m) == 0 {
		return "null", nil
	}
	return string(m), nil
}

// MarshalJSON returns m as the JSON encoding of m.
func (m JSONRawMessage) MarshalJSON() ([]byte, error) {
	if len(m) == 0 {
		return []byte("null"), nil
	}
	return m, nil

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Cast the column in SQL to text/json: SELECT col::text AS col so the driver returns a string or []byte.
  2. Prefer the pq/postgres driver or configure the driver to return strings for JSON columns.
  3. Change the field type to match what the driver actually returns (e.g. string, []byte) and convert manually.

Example fix

// before
rows.QueryRow("SELECT metadata FROM events").Scan(&raw) // raw is sqlxx.JSONRawMessage, driver returns float64
// after
rows.QueryRow("SELECT metadata::text AS metadata FROM events").Scan(&raw)
Defensive patterns

Strategy: type-guard

Validate before calling

switch v := dbValue.(type) {
case []byte, string, nil:
    // safe to Scan into JSONRawMessage
default:
    // convert first: fmt.Sprintf("%v", v) or marshal v
}

Type guard

func scannableIntoJSONRawMessage(v any) bool {
    switch v.(type) {
    case []byte, string, nil:
        return true
    default:
        return false
    }
}

Try / catch

// value is *errors.Error from oryx/pkg/errors
var raw sqlxx.JSONRawMessage
if err := row.Scan(&raw); err != nil {
    if strings.Contains(err.Error(), "cannot scan") {
        var s string
        if e2 := row.Scan(&s); e2 == nil {
            raw = sqlxx.JSONRawMessage(s)
        }
    }
}

Prevention

When it happens

Trigger: Scanning a column into JSONRawMessage when the database driver returns a type other than []byte, string, or nil — e.g. some drivers return numeric/text columns as int64, float64, or time.Time.

Common situations: Using a driver that decodes JSON columns differently (Postgres drivers usually give []byte, but SQLite or MySQL drivers may return string variants or other types); mapping a non-JSON column into a JSONRawMessage field.

Related errors


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