{"record":{"id":"8b44caf60172ab37","repo":"ory/hydra","slug":"unable-to-scan-type-t-as-json-into-t","errorCode":null,"errorMessage":"unable to scan type %T as JSON into %T","messagePattern":"unable to scan type %T as JSON into %T","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/sqlxx/types.go","lineNumber":501,"sourceCode":"// UnmarshalJSON sets *m to a copy of data.\nfunc (m *NullJSONObject) UnmarshalJSON(data []byte) error {\n\treturn (*NullJSONRawMessage)(m).UnmarshalJSON(data)\n}\n\n// JSONScan is a generic helper for retrieving a SQL JSON-encoded value.\nfunc JSONScan(dst, value any) error {\n\t// Note: raw is a string (not []byte) because the MySQL driver reuses byte slices across scans.\n\t// Using strings avoids the need to manually copy the byte slice.\n\tvar raw string\n\tswitch v := value.(type) {\n\tcase nil:\n\t\traw = \"null\"\n\tcase string:\n\t\traw = v\n\tcase []byte:\n\t\traw = string(v)\n\tdefault:\n\t\treturn fmt.Errorf(\"unable to scan type %T as JSON into %T\", value, dst)\n\t}\n\tif err := json.Unmarshal([]byte(raw), dst); err != nil {\n\t\treturn fmt.Errorf(\"unable to decode JSON payload into %T: %w\", dst, err)\n\t}\n\treturn nil\n}\n\n// NullInt64 represents an int64 that may be null.\n// swagger:type int64\n// swagger:model nullInt64\ntype NullInt64 struct {\n\tInt   int64\n\tValid bool // Valid is true if Duration is not NULL\n}\n\n// Scan implements the Scanner interface.\nfunc (ns *NullInt64) Scan(value interface{}) error {\n\td := sql.NullInt64{}","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/sqlxx/types.go#L483-L519","documentation":"JSONScan scans a database value (string, []byte, or null) into a destination pointer via json.Unmarshal. It throws this error when the value passed by the database driver is of an unsupported Go type (e.g. int, time.Time, []interface{}), because it cannot convert it to raw JSON text to unmarshal. It indicates a driver/type mismatch rather than invalid JSON.","triggerScenarios":"Scanning a column whose driver returns a native non-string type (e.g. a JSONB returned as a parsed value, an int, or time.Time) into a field whose Scan delegates to JSONScan (e.g. a JSON/JSONB or nullable JSON column mapped to a custom type wrapping this helper).","commonSituations":"Using a driver that decodes JSON columns into map[string]interface{} instead of []byte (e.g. certain pq/pgx or sqlite drivers), storing JSON in a non-text column type, or ORM scanning a numeric/boolean column into a JSON-typed struct field.","solutions":["Check the actual Go type the driver returns for the column (log %T of the value) and pick a driver setting that returns strings/[]byte for JSON columns","Ensure the DB column is a text/JSON type that the driver delivers as string or []byte","Implement a custom Scan on the destination type that handles the driver's concrete type (e.g. convert numbers/bools with json.Marshal before unmarshal)","Do not bind JSONScan-backed types to columns that are not JSON/text"],"exampleFix":"// before: driver returns map for JSONB column\nfunc (j *JSONB) Scan(value interface{}) error { return JSONScan(value, j) }\n// after: normalize unsupported types first\nfunc (j *JSONB) Scan(value interface{}) error {\n    switch v := value.(type) {\n    case []byte, string, nil:\n        return JSONScan(value, j)\n    default:\n        b, err := json.Marshal(value)\n        if err != nil { return err }\n        return JSONScan(b, j)\n    }\n}","handlingStrategy":"validation","validationCode":"func canJSONScan(value interface{}) bool {\n    switch value.(type) {\n    case nil, string, []byte:\n        return true\n    default:\n        return false\n    }\n}","typeGuard":"func isJSONScanable(v interface{}) bool {\n    switch v.(type) {\n    case nil, string, []byte:\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Log %T of driver values for JSON columns to know what the driver returns","Configure the driver to return JSON columns as string/[]byte","Only bind JSONScan-backed types to text/JSON columns"],"tags":["json","database","scan","type-mismatch"],"backgroundTag":"sql-scan-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"}