{"record":{"id":"a80813ff86458032","repo":"ory/hydra","slug":"expected-json-value-to-be-an-array-but-got-type","errorCode":null,"errorMessage":"expected JSON value to be an array but got type: %s","messagePattern":"expected JSON value to be an array but got type: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/sqlxx/types.go","lineNumber":70,"sourceCode":"\tswitch v := value.(type) {\n\tcase nil:\n\t\t*m = StringSliceJSONFormat{}\n\t\treturn nil\n\tcase string:\n\t\tval = v\n\tcase []byte:\n\t\tval = string(v)\n\tdefault:\n\t\treturn errors.Errorf(\"cannot scan %#v into StringSliceJSONFormat\", value)\n\t}\n\tif len(val) == 0 {\n\t\tval = \"[]\"\n\t}\n\n\tif parsed := gjson.Parse(val); parsed.Type == gjson.Null {\n\t\tval = \"[]\"\n\t} else if !parsed.IsArray() {\n\t\treturn errors.Errorf(\"expected JSON value to be an array but got type: %s\", parsed.Type.String())\n\t}\n\n\treturn errors.WithStack(json.Unmarshal([]byte(val), &m))\n}\n\n// Value implements the driver Valuer interface.\nfunc (m StringSliceJSONFormat) Value() (driver.Value, error) {\n\tif len(m) == 0 {\n\t\treturn \"[]\", nil\n\t}\n\n\tencoded, err := json.Marshal(&m)\n\treturn string(encoded), errors.WithStack(err)\n}\n\n// StringSlicePipeDelimiter de/encodes the string slice to/from a SQL string.\ntype StringSlicePipeDelimiter []string\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/sqlxx/types.go#L52-L88","documentation":"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.","triggerScenarios":"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.","commonSituations":"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\"]`.","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."],"exampleFix":"// before\nmeta := map[string]string{\"k\": \"v\"}\ndb.Exec(\"UPDATE items SET tags = ?\", mustJSON(meta)) // writes object -> Scan fails\n\n// after\ntags := []string{\"a\", \"b\"}\ndb.Exec(\"UPDATE items SET tags = ?\", mustJSON(tags)) // writes [\"a\",\"b\"]","handlingStrategy":"validation","validationCode":"// validate stored value is a JSON array before scanning\ndoc, _ := io.ReadAll(rows)\nif gjson.Parse(string(doc)).Type != gjson.Null && !gjson.Parse(string(doc)).IsArray() {\n    return fmt.Errorf(\"expected JSON array in column, got: %s\", string(doc))\n}","typeGuard":"func isJSONArrayDoc(s string) bool {\n    p := gjson.Parse(s)\n    return p.Type == gjson.Null || p.IsArray()\n}","tryCatchPattern":"var tags sqlxx.StringSliceJSONFormat\nif err := rows.Scan(&tags); err != nil {\n    if strings.Contains(err.Error(), \"expected JSON value to be an array\") {\n        // legacy/object-shaped row: normalize or surface a data-migration error\n        return fmt.Errorf(\"row has non-array JSON in tags column: %w\", err)\n    }\n    return err\n}","preventionTips":["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."],"tags":["database","json","scan","type-mismatch"],"backgroundTag":"json-type-mismatch","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}