{"record":{"id":"e3d1e8cca1b81b3d","repo":"jmoiron/sqlx","slug":"nil-pointer-passed-to-structscan-destination","errorCode":null,"errorMessage":"nil pointer passed to StructScan destination","messagePattern":"nil pointer passed to StructScan destination","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sqlx.go","lineNumber":755,"sourceCode":"\treturn MapScan(r, dest)\n}\n\nfunc (r *Row) scanAny(dest interface{}, structOnly bool) error {\n\tif r.err != nil {\n\t\treturn r.err\n\t}\n\tif r.rows == nil {\n\t\tr.err = sql.ErrNoRows\n\t\treturn r.err\n\t}\n\tdefer r.rows.Close()\n\n\tv := reflect.ValueOf(dest)\n\tif v.Kind() != reflect.Ptr {\n\t\treturn errors.New(\"must pass a pointer, not a value, to StructScan destination\")\n\t}\n\tif v.IsNil() {\n\t\treturn errors.New(\"nil pointer passed to StructScan destination\")\n\t}\n\n\tbase := reflectx.Deref(v.Type())\n\tscannable := isScannable(base)\n\n\tif structOnly && scannable {\n\t\treturn structOnlyError(base)\n\t}\n\n\tcolumns, err := r.Columns()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif scannable && len(columns) > 1 {\n\t\treturn fmt.Errorf(\"scannable dest type %s with >1 columns (%d) in result\", base.Kind(), len(columns))\n\t}\n","sourceCodeStart":737,"sourceCodeEnd":773,"githubUrl":"https://github.com/jmoiron/sqlx/blob/41dac167fdad5e3fd81d66cafba0951dc6823a30/sqlx.go#L737-L773","documentation":"A typed nil pointer (e.g. var u *User; rows.StructScan(u)) passes the Kind()==Ptr check but points at nothing. reflect cannot allocate storage through a nil pointer, so sqlx explicitly rejects nil destinations before attempting the scan.","triggerScenarios":"Calling StructScan with a declared-but-uninitialized pointer: var u *User; rows.StructScan(u), or a function parameter of pointer type that the caller left nil.","commonSituations":"Pointer-typed fields in larger structs left nil; helper functions taking *T parameters called with nil; refactors from value to pointer semantics without allocation.","solutions":["Allocate before scanning: u := &User{}; rows.StructScan(u)","Use a value variable and take its address: var u User; rows.StructScan(&u)","Inside helpers, check reflect.ValueOf(dest).IsNil() and allocate via reflect.New","Prefer Get/Select which construct destinations for you"],"exampleFix":"// before\nvar u *User\nrows.StructScan(u)\n// after\nu := &User{}\nrows.StructScan(u)","handlingStrategy":"validation","validationCode":"func safeStructScan(rows *sqlx.Rows, dest interface{}) error {\n    v := reflect.ValueOf(dest)\n    if v.Kind() != reflect.Ptr || v.IsNil() {\n        return fmt.Errorf(\"StructScan needs a non-nil pointer, got %T\", dest)\n    }\n    return rows.StructScan(dest)\n}","typeGuard":"func isNonNilPointer(dest interface{}) bool {\n    v := reflect.ValueOf(dest)\n    return v.Kind() == reflect.Ptr && !v.IsNil()\n}","tryCatchPattern":"if err := rows.StructScan(u); err != nil {\n    if strings.Contains(err.Error(), \"nil pointer\") {\n        return fmt.Errorf(\"allocate destination before scan (u = &User{}): %w\", err)\n    }\n    return err\n}","preventionTips":["Initialize pointer destinations: dest := &User{} before scanning","Avoid passing pointer-typed function parameters straight to StructScan without a nil check","Prefer value variables plus & for scan destinations"],"tags":["go","sqlx","structscan","nil-pointer"],"backgroundTag":"nil-pointer-scan-destination","analyzedSha":"41dac167fdad5e3fd81d66cafba0951dc6823a30","analyzedAt":"2026-09-03T06:10:20.382Z","contentChangedAt":"2026-09-03T06:10:20.382Z","schemaVersion":2},"datasetVersion":"2026-09-10T12:17:11.382Z"}