{"id":"25a278165b16da5f","repo":"go-redis/redis","slug":"redis-multi-shard-command-s-has-no-key-arguments","errorCode":null,"errorMessage":"redis: multi-shard command %s has no key arguments","messagePattern":"redis: multi-shard command (.+?) has no key arguments","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"osscluster_router.go","lineNumber":122,"sourceCode":"\n\tif len(state.Masters) == 0 {\n\t\treturn errClusterNoNodes\n\t}\n\n\treturn c.executeParallel(ctx, cmd, state.Masters, policy)\n}\n\n// executeMultiShard handles commands that operate on multiple keys across shards\nfunc (c *ClusterClient) executeMultiShard(ctx context.Context, cmd Cmder, policy *routing.CommandPolicy) error {\n\targs := cmd.Args()\n\tfirstKeyPos := cmdFirstKeyPosWithInfo(cmd, c.cmdInfoPeek(cmd.Name()))\n\tstepCount := int(cmd.stepCount())\n\tif stepCount == 0 {\n\t\tstepCount = 1 // Default to 1 if not set\n\t}\n\n\tif firstKeyPos == 0 || firstKeyPos >= len(args) {\n\t\treturn fmt.Errorf(\"redis: multi-shard command %s has no key arguments\", cmd.Name())\n\t}\n\n\t// Group keys by slot\n\tslotMap := make(map[int][]string)\n\tkeyOrder := make([]string, 0)\n\n\tfor i := firstKeyPos; i < len(args); i += stepCount {\n\t\tkey, ok := args[i].(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"redis: non-string key at position %d: %v\", i, args[i])\n\t\t}\n\n\t\tslot := hashtag.Slot(key)\n\t\tslotMap[slot] = append(slotMap[slot], key)\n\t\tfor j := 1; j < stepCount; j++ {\n\t\t\tif i+j >= len(args) {\n\t\t\t\tbreak\n\t\t\t}","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/osscluster_router.go#L104-L140","documentation":"Returned by executeMultiShard when a command classified as multi-shard (ReqMultiShard) has no key arguments at the expected position. The router derives firstKeyPos from command metadata; if it is 0 or beyond the argument list, the command cannot be split across shards and is rejected.","triggerScenarios":"Calling a multi-key command (e.g. MSET, DEL with multiple keys, or a module command with multi-shard policy) with zero keys, or with arguments where the key position does not line up with the command's declared key spec. Also if a custom Cmder reports the wrong step/first-key metadata.","commonSituations":"Dynamically building an argument list that ends up empty, a wrapper that drops key arguments, or a command-policy/key-spec mismatch for a module command.","solutions":["Ensure the command is called with at least one key argument at the expected position.","For dynamic builders, guard against an empty key slice before issuing the command.","If using a module command, verify its key spec / command policy is registered correctly."],"exampleFix":"// before\nclient.Do(ctx, \"MSET\")\n// after\nclient.Do(ctx, \"MSET\", \"k1\", \"v1\", \"k2\", \"v2\")","handlingStrategy":"validation","validationCode":"func hasKeyArgs(cmd redis.Cmder) bool {\n    args := cmd.Args()\n    return len(args) >= 2 // command name + at least one key\n}","typeGuard":null,"tryCatchPattern":"if err := cmd.Err(); err != nil && strings.Contains(err.Error(), \"has no key arguments\") {\n    // ensure the argument list contains at least one key before re-issuing\n}","preventionTips":["Guard dynamic argument builders against empty key slices.","Validate that multi-key commands receive at least one key.","For module commands, register the correct key spec / command policy."],"tags":["cluster","routing","validation"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}