{"record":{"id":"81bf7342bbdb206b","repo":"jmoiron/sqlx","slug":"argument-not-a-struct","errorCode":null,"errorMessage":"argument not a struct","messagePattern":"argument not a struct","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sqlx.go","lineNumber":1029,"sourceCode":"\nfunc baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {\n\tt = reflectx.Deref(t)\n\tif t.Kind() != expected {\n\t\treturn nil, fmt.Errorf(\"expected %s but got %s\", expected, t.Kind())\n\t}\n\treturn t, nil\n}\n\n// fieldsByName fills a values interface with fields from the passed value based\n// on the traversals in int.  If ptrs is true, return addresses instead of values.\n// We write this instead of using FieldsByName to save allocations and map lookups\n// when iterating over many rows.  Empty traversals will get an interface pointer.\n// Because of the necessity of requesting ptrs or values, it's considered a bit too\n// specialized for inclusion in reflectx itself.\nfunc fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{}, ptrs bool) error {\n\tv = reflect.Indirect(v)\n\tif v.Kind() != reflect.Struct {\n\t\treturn errors.New(\"argument not a struct\")\n\t}\n\n\tfor i, traversal := range traversals {\n\t\tif len(traversal) == 0 {\n\t\t\tvalues[i] = new(interface{})\n\t\t\tcontinue\n\t\t}\n\t\tf := reflectx.FieldByIndexes(v, traversal)\n\t\tif ptrs {\n\t\t\tvalues[i] = f.Addr().Interface()\n\t\t} else {\n\t\t\tvalues[i] = f.Interface()\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc missingFields(transversals [][]int) (field int, err error) {","sourceCodeStart":1011,"sourceCodeEnd":1047,"githubUrl":"https://github.com/jmoiron/sqlx/blob/41dac167fdad5e3fd81d66cafba0951dc6823a30/sqlx.go#L1011-L1047","documentation":"fieldsByTraversal is used by StructScan-style helpers in sqlx to map database columns onto fields of a struct via reflectx traversals. It indirects the destination value and requires it to be (a pointer to) a struct; if the underlying kind is not struct it cannot receive the scanned fields, so it returns this error. The library throws it because column-to-field mapping is only meaningful for structs.","triggerScenarios":"Calling StructScan/Scan with a destination that is a pointer to a non-struct (e.g. *int, *[]string) or a nil pointer that reflects to a non-struct after Indirect, while the query returned columns (traversals were computed for a struct).","commonSituations":"Scanning a single-column result into *int via StructScan instead of db.Get(&intVar); passing **T where T is not a struct; passing an unaddressable value like map[string]interface{}; accidentally using StructScan on Rows for scalar queries.","solutions":["Ensure the destination passed to StructScan is a *struct (or pointer to slice of structs for Select).","Use Get/Select/ScanRow for scalar or slice-of-scalar results instead of StructScan.","Check that the pointer is non-nil before calling StructScan.","Verify the reflect.Value being scanned actually points at a struct kind."],"exampleFix":"// before\nvar count int\nrows.StructScan(&count)\n// after\nvar row struct{ Count int }\nrows.StructScan(&row)","handlingStrategy":"type-guard","validationCode":"func isStructPtr(v interface{}) bool {\n\tr := reflect.Indirect(reflect.ValueOf(v))\n\treturn r.Kind() == reflect.Struct && r.CanAddr()\n}\n// if !isStructPtr(dest) { use Get/Scan instead of StructScan }","typeGuard":"func asStructPtr(v interface{}) (bool, string) {\n\tr := reflect.Indirect(reflect.ValueOf(v))\n\tif r.Kind() != reflect.Struct {\n\t\treturn false, fmt.Sprintf(\"got %s, want struct\", r.Kind())\n\t}\n\treturn true, \"\"\n}","tryCatchPattern":"var row MyStruct\nif err := rows.StructScan(&row); err != nil {\n\tif err.Error() == \"argument not a struct\" {\n\t\t// fall back to rows.Scan(&scalar) for non-struct destinations\n\t}\n\treturn err\n}","preventionTips":["Always pass *T where T is a struct to StructScan.","Use Get/Select/Scan for scalars and slices of scalars.","Never pass a nil pointer destination to StructScan.","Double-check you are not passing *[]T to StructScan — that is for Select."],"tags":["sql","reflection","scan","struct"],"backgroundTag":"scan-destination-not-struct","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"}