{"record":{"id":"3a61fc5db173b8d2","repo":"knadh/listmonk","slug":"could-not-not-decode-type-t-t","errorCode":null,"errorMessage":"could not not decode type %T -> %T","messagePattern":"could not not decode type %T -> %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"models/common.go","lineNumber":133,"sourceCode":"// StringIntMap is used to define DB Scan()s.\ntype StringIntMap map[string]int\n\n// Value returns the JSON marshalled SubscriberAttribs.\nfunc (s JSON) Value() (driver.Value, error) {\n\treturn json.Marshal(s)\n}\n\n// Scan unmarshals JSONB from the DB.\nfunc (s JSON) Scan(b any) error {\n\tif b == nil {\n\t\ts = make(JSON)\n\t\treturn nil\n\t}\n\n\tif data, ok := b.([]byte); ok {\n\t\treturn json.Unmarshal(data, &s)\n\t}\n\treturn fmt.Errorf(\"could not not decode type %T -> %T\", b, s)\n}\n\n// Scan unmarshals JSONB from the DB.\nfunc (s StringIntMap) Scan(src any) error {\n\tif src == nil {\n\t\ts = make(StringIntMap)\n\t\treturn nil\n\t}\n\n\tif data, ok := src.([]byte); ok {\n\t\treturn json.Unmarshal(data, &s)\n\t}\n\treturn fmt.Errorf(\"could not not decode type %T -> %T\", src, s)\n}\n\n// Scan implements the sql.Scanner interface.\nfunc (h *Headers) Scan(src any) error {\n\tvar b []byte","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/knadh/listmonk/blob/670c01717d48647093335cc23a6be6f4b79c3b6b/models/common.go#L115-L151","documentation":"StringIntMap implements sql.Scanner; Scan expects nil or []byte (JSONB from Postgres). If the driver delivers any other Go type, json.Unmarshal can't be attempted and this (typo'd) error is returned describing the source and target types.","triggerScenarios":"Database/driver returns a value that is neither nil nor []byte — e.g. a string instead of []byte — when scanning a JSONB column into StringIntMap.","commonSituations":"Using a driver or scan helper that decodes JSONB into string instead of []byte; hand-written queries casting the column (e.g. ::text); unit tests passing string values to Scan.","solutions":["Add a string case: if data, ok := b.(string); ok { return json.Unmarshal([]byte(data), &s) }","Ensure the query doesn't cast the JSONB column to text; select it as-is so the driver returns []byte","Pass []byte(...) when calling Scan directly in tests/code"],"exampleFix":"// before\nif data, ok := b.([]byte); ok {\n    return json.Unmarshal(data, &s)\n}\n// after\nswitch data := b.(type) {\ncase []byte:\n    return json.Unmarshal(data, &s)\ncase string:\n    return json.Unmarshal([]byte(data), &s)\n}","handlingStrategy":"type-guard","validationCode":"switch v := value.(type) {\ncase nil, []byte:\n    // OK to pass to Scan\ncase string:\n    value = []byte(v)\ndefault:\n    return fmt.Errorf(\"cannot scan %T into StringIntMap\", value)\n}","typeGuard":"func isScannableJSONB(v any) bool {\n    switch v.(type) {\n    case nil, []byte, string:\n        return true\n    }\n    return false\n}","tryCatchPattern":"if err := m.Scan(dbValue); err != nil {\n    if strings.Contains(err.Error(), \"could not not decode\") {\n        // coerce dbValue to []byte (if string) and retry once\n    }\n}","preventionTips":["Select JSONB columns without ::text casts","Pin a single Postgres driver so JSONB consistently arrives as []byte","Extend Scan with a string case for defensive parsing"],"tags":["database","json","scan"],"backgroundTag":"unsupported-scan-type","analyzedSha":"670c01717d48647093335cc23a6be6f4b79c3b6b","analyzedAt":"2026-09-01T03:39:35.452Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}