{"record":{"id":"b6d38aff38489b6f","repo":"kataras/iris","slug":"sqlx-bind-destination-not-a-pointer","errorCode":null,"errorMessage":"sqlx: bind: destination not a pointer","messagePattern":"sqlx: bind: destination not a pointer","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/sqlx/sqlx.go","lineNumber":118,"sourceCode":"func (s *Schema) Query(ctx context.Context, db *sql.DB, dst any, query string, args ...any) error {\n\trows, err := db.QueryContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !s.AutoCloseRows { // if not close on bind, we must close it here.\n\t\tdefer rows.Close()\n\t}\n\n\terr = s.Bind(dst, rows)\n\treturn err\n}\n\n// Bind sets \"dst\" to the result of \"src\" and reports any errors.\nfunc (s *Schema) Bind(dst any, src *sql.Rows) error {\n\ttyp := reflect.TypeOf(dst)\n\tif typ.Kind() != reflect.Ptr {\n\t\treturn fmt.Errorf(\"sqlx: bind: destination not a pointer\")\n\t}\n\n\ttyp = typ.Elem()\n\n\toriginalKind := typ.Kind()\n\tif typ.Kind() == reflect.Slice {\n\t\ttyp = typ.Elem()\n\t}\n\n\tr, ok := s.Rows[typ]\n\tif !ok {\n\t\treturn fmt.Errorf(\"sqlx: bind: unregistered type: %q\", typ.String())\n\t}\n\n\tcolumnTypes, err := src.ColumnTypes()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sqlx: bind: table: %q: %w\", r.Name, err)\n\t}","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/x/sqlx/sqlx.go#L100-L136","documentation":"Schema.Bind reflects on dst to discover the target struct or slice-of-struct type. If dst is not a pointer (e.g. a struct value or a struct passed by value), reflection cannot write results into it, so Bind returns \"sqlx: bind: destination not a pointer\" before touching the rows.","triggerScenarios":"sqlx.Query(ctx, db, User{}, ...) or s.Bind(User{}, rows) — passing a struct value instead of &user / &users.","commonSituations":"Forgetting & in the dst argument; capturing the struct in a variable typed as any holding a non-pointer; refactors that drop the address-of operator.","solutions":["Pass a pointer: sqlx.Query(ctx, db, &user, query) or &users for a slice.","If dst comes from an interface, ensure it was initialized as a pointer (reflect.New(typ).Interface()).","Add a compile-time helper or lint to require pointer receivers for scan destinations."],"exampleFix":"// before\nvar user User\nsqlx.Query(ctx, db, user, \"SELECT * FROM users LIMIT 1\") // error\n// after\nsqlx.Query(ctx, db, &user, \"SELECT * FROM users LIMIT 1\")","handlingStrategy":"validation","validationCode":"func ensurePtr(dst any) error {\n\tif reflect.TypeOf(dst).Kind() != reflect.Ptr {\n\t\treturn errors.New(\"sqlx: bind: destination not a pointer\")\n\t}\n\treturn nil\n}\n// call before sqlx.Query / Bind","typeGuard":"func isPointer(dst any) bool { return reflect.TypeOf(dst).Kind() == reflect.Ptr }","tryCatchPattern":"if err := sqlx.Query(ctx, db, &user, query); err != nil {\n\tif err.Error() == \"sqlx: bind: destination not a pointer\" {\n\t\treturn fmt.Errorf(\"pass &user (a pointer) as dst: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Always pass &struct or &slice to Query/Bind","Keep dst typed as a concrete pointer, not any holding a value","Enable linters that flag non-pointer scan destinations"],"tags":["go","sql","reflection","sqlx","bind"],"backgroundTag":"destination-not-pointer","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}