{"record":{"id":"49e0030ae7a310a5","repo":"redis/go-redis","slug":"both-libname-and-libver-cannot-be-set-at-the-same","errorCode":null,"errorMessage":"both LibName and LibVer cannot be set at the same time","messagePattern":"both LibName and LibVer cannot be set at the same time","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"commands.go","lineNumber":351,"sourceCode":"\t\tpanic(err.Error())\n\t}\n\n\tvar cmd *StatusCmd\n\tif info.LibName != nil {\n\t\tlibName := fmt.Sprintf(\"go-redis(%s,%s)\", *info.LibName, internal.ReplaceSpaces(runtime.Version()))\n\t\tcmd = NewStatusCmd(ctx, \"client\", \"setinfo\", \"LIB-NAME\", libName)\n\t} else {\n\t\tcmd = NewStatusCmd(ctx, \"client\", \"setinfo\", \"LIB-VER\", *info.LibVer)\n\t}\n\n\t_ = c(ctx, cmd)\n\treturn cmd\n}\n\n// Validate checks if only one field in the struct is non-nil.\nfunc (info LibraryInfo) Validate() error {\n\tif info.LibName != nil && info.LibVer != nil {\n\t\treturn errors.New(\"both LibName and LibVer cannot be set at the same time\")\n\t}\n\tif info.LibName == nil && info.LibVer == nil {\n\t\treturn errors.New(\"at least one of LibName and LibVer should be set\")\n\t}\n\treturn nil\n}\n\n// Hello sets the resp protocol used.\nfunc (c statefulCmdable) Hello(ctx context.Context,\n\tver int, username, password, clientName string,\n) *MapStringInterfaceCmd {\n\targs := make([]interface{}, 0, 7)\n\targs = append(args, \"hello\", ver)\n\tif password != \"\" {\n\t\tif username != \"\" {\n\t\t\targs = append(args, \"auth\", username, password)\n\t\t} else {\n\t\t\targs = append(args, \"auth\", \"default\", password)","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/redis/go-redis/blob/c5cad058c72f58370553b48566302303cf8a2e89/commands.go#L333-L369","documentation":"LibraryInfo.Validate enforces that a CLIENT SETINFO command sets exactly one of LibName or LibVer. The go-redis API exposes these as *string pointers so nil vs empty can be distinguished, and passing both is rejected because the Redis CLIENT SETINFO protocol accepts only one attribute per call.","triggerScenarios":"Calling ClientSetInfo with a LibraryInfo where both LibName and LibVer are non-nil, e.g. redis.LibraryInfo{LibName: redis.StringPtr(\"myapp\"), LibVer: redis.StringPtr(\"1.2.0\")}.","commonSituations":"Developers assuming the method sends both attributes at once, or trying to mirror the redis-cli syntax; wrapping what should be two calls into one struct.","solutions":["Set only one field per LibraryInfo value and issue two ClientSetInfo calls: one for LibName, one for LibVer.","If you only need the library name, drop LibVer from the struct.","If you only need the version, drop LibName."],"exampleFix":"// before\nrdb.ClientSetInfo(ctx, redis.LibraryInfo{LibName: redis.StringPtr(\"myapp\"), LibVer: redis.StringPtr(\"1.0\")})\n// after\nrdb.ClientSetInfo(ctx, redis.LibraryInfo{LibName: redis.StringPtr(\"myapp\")})\nrdb.ClientSetInfo(ctx, redis.LibraryInfo{LibVer: redis.StringPtr(\"1.0\")})","handlingStrategy":"validation","validationCode":"func validLibInfo(info redis.LibraryInfo) bool {\n    return (info.LibName == nil) != (info.LibVer == nil)\n}\nif !validLibInfo(info) { /* fix before calling */ }","typeGuard":"func hasExactlyOne(info redis.LibraryInfo) bool {\n    n := 0\n    if info.LibName != nil { n++ }\n    if info.LibVer != nil { n++ }\n    return n == 1\n}","tryCatchPattern":null,"preventionTips":["Send LibName and LibVer as two separate ClientSetInfo calls.","Use redis.StringPtr explicitly so nil-vs-empty is intentional.","Add a unit test asserting exactly one field is set."],"tags":["client-setinfo","validation","configuration"],"backgroundTag":"client-setinfo-validation","analyzedSha":"c5cad058c72f58370553b48566302303cf8a2e89","analyzedAt":"2026-09-01T06:50:53.388Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}