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, nilView on GitHub (pinned to 4174065ffb)
Solutions
- Cast the column in SQL to text/json: SELECT col::text AS col so the driver returns a string or []byte.
- Prefer the pq/postgres driver or configure the driver to return strings for JSON columns.
- 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
- Cast JSON columns to text in SQL (col::text) so drivers return strings/bytes.
- Prefer drivers known to return []byte/string for JSON columns (lib/pq, pgx default).
- Do not map non-JSON columns (numeric, timestamp) into JSONRawMessage fields.
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
- cookiex: payload must be a flat JSON object with string valu
- unable to scan type %T as JSON into %T
- cannot scan %#v into StringSliceJSONFormat
- expected JSON value to be an array but got type: %s
- unable to decode JSON: %w
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/7060da732dcebaf9.
Report an issue: GitHub.