ory/hydra · error
expected JSON value to be an array but got type: %s
Error message
expected JSON value to be an array but got type: %s
What it means
After decoding the scanned text, StringSliceJSONFormat.Scan checks that the JSON value is actually an array before unmarshalling into []string. If the stored document is an object, string, number, or boolean, it returns this error with the gjson type name. The database column contains valid JSON but of the wrong shape for a string slice.
Source
Thrown at oryx/sqlxx/types.go:70
switch v := value.(type) {
case nil:
*m = StringSliceJSONFormat{}
return nil
case string:
val = v
case []byte:
val = string(v)
default:
return errors.Errorf("cannot scan %#v into StringSliceJSONFormat", value)
}
if len(val) == 0 {
val = "[]"
}
if parsed := gjson.Parse(val); parsed.Type == gjson.Null {
val = "[]"
} else if !parsed.IsArray() {
return errors.Errorf("expected JSON value to be an array but got type: %s", parsed.Type.String())
}
return errors.WithStack(json.Unmarshal([]byte(val), &m))
}
// Value implements the driver Valuer interface.
func (m StringSliceJSONFormat) Value() (driver.Value, error) {
if len(m) == 0 {
return "[]", nil
}
encoded, err := json.Marshal(&m)
return string(encoded), errors.WithStack(err)
}
// StringSlicePipeDelimiter de/encodes the string slice to/from a SQL string.
type StringSlicePipeDelimiter []string
View on GitHub (pinned to 4174065ffb)
Solutions
- Fix the writer so it marshals []string (ensuring `json.Marshal` is called on a slice, producing `["a","b"]`).
- Migrate existing bad rows: UPDATE t SET col = ... to convert objects/scalars into arrays (e.g. wrap scalars: jsonb_build_array(col)).
- If the data is genuinely an object, change the model to a matching type (e.g. a map/string-map type) instead of StringSliceJSONFormat.
- Add a read-side normalization step that converts legacy shapes to arrays before assignment.
Example fix
// before
meta := map[string]string{"k": "v"}
db.Exec("UPDATE items SET tags = ?", mustJSON(meta)) // writes object -> Scan fails
// after
tags := []string{"a", "b"}
db.Exec("UPDATE items SET tags = ?", mustJSON(tags)) // writes ["a","b"] Defensive patterns
Strategy: validation
Validate before calling
// validate stored value is a JSON array before scanning
doc, _ := io.ReadAll(rows)
if gjson.Parse(string(doc)).Type != gjson.Null && !gjson.Parse(string(doc)).IsArray() {
return fmt.Errorf("expected JSON array in column, got: %s", string(doc))
} Type guard
func isJSONArrayDoc(s string) bool {
p := gjson.Parse(s)
return p.Type == gjson.Null || p.IsArray()
} Try / catch
var tags sqlxx.StringSliceJSONFormat
if err := rows.Scan(&tags); err != nil {
if strings.Contains(err.Error(), "expected JSON value to be an array") {
// legacy/object-shaped row: normalize or surface a data-migration error
return fmt.Errorf("row has non-array JSON in tags column: %w", err)
}
return err
} Prevention
- Always write through json.Marshal on a []string so the column stores ["a","b"].
- Add a data migration that rewrites legacy objects/scalars into arrays.
- Enforce the column shape with a CHECK constraint (jsonb_typeof(col) = 'array').
- Cover both write and read paths with round-trip tests for JSON-typed fields.
When it happens
Trigger: Scanning a text/JSON column whose content is `{...}` (object), `"text"`, `123`, or `true` into a *StringSliceJSONFormat; an application bug writing a JSON object where an array was expected; legacy rows written by an older schema version using a different shape.
Common situations: Mixed-version writers: new code writes an object, old reader expects an array; hand-edited DB rows; importing data from another system where the field was a map; a single-value column that stores `"foo"` (JSON string) instead of `["foo"]`.
Related errors
- unable to scan type %T as JSON into %T
- cannot scan %#v into StringSliceJSONFormat
- cannot scan %T into region.Region
- cookiex: payload must be a flat JSON object with string valu
- unable to decode JSON payload into %T: %w
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/a80813ff86458032.
Report an issue: GitHub.