{"record":{"id":"9e168e803158da59","repo":"redis/node-redis","slug":"cannot-split-label-key-region-overruns-the-arg","errorCode":null,"errorMessage":"Cannot split ${label}: key region overruns the arguments","messagePattern":"Cannot split (.+?): key region overruns the arguments","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/client/lib/cluster/request-response-policies/multi-shard-splitter.ts","lineNumber":105,"sourceCode":"      if (keyNumIdx >= keyRegionStart) {\n        throw new Error(`Cannot split ${label}: numkeys argument inside the key region`);\n      }\n      const numKeys = parsePositiveInteger(args[keyNumIdx]);\n      if (numKeys === undefined) {\n        throw new Error(`Cannot split ${label}: malformed numkeys argument '${args[keyNumIdx]}'`);\n      }\n      keyRegionEnd = keyRegionStart + numKeys * keyStep;\n      break;\n    }\n    default:\n      throw new Error(`Cannot split ${label}: unsupported find_keys type '${findKeys.type}'`);\n  }\n\n  if (keyStep < 1) {\n    throw new Error(`Cannot split ${label}: invalid keystep ${keyStep}`);\n  }\n  if (keyRegionStart < 1 || keyRegionEnd > args.length) {\n    throw new Error(`Cannot split ${label}: key region overruns the arguments`);\n  }\n  const regionLength = keyRegionEnd - keyRegionStart;\n  if (regionLength <= 0 || regionLength % keyStep !== 0) {\n    throw new Error(`Cannot split ${label}: key region does not align with keystep ${keyStep}`);\n  }\n\n  const groupCount = regionLength / keyStep;\n  const slotGroups = new Map<number, Array<number>>();\n  for (let group = 0; group < groupCount; group++) {\n    const slot = calculateSlot(args[keyRegionStart + group * keyStep]);\n    const groups = slotGroups.get(slot);\n    if (groups) {\n      groups.push(group);\n    } else {\n      slotGroups.set(slot, [group]);\n    }\n  }\n","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/client/lib/cluster/request-response-policies/multi-shard-splitter.ts#L87-L123","documentation":"The computed key region (the span of arguments holding keys) extends beyond the actual argument list. For a command like MSET the splitter expects keys starting at index 1 through the end of args; if args are too short the region overruns and the split is rejected to avoid reading undefined positions.","triggerScenarios":"Calling a multi_shard command (DEL, UNLINK, EXISTS, TOUCH, MGET, MSET) via sendCommand with raw arguments that are too short, e.g. sendCommand('MSET','key1') where MSET expects at least a key and value at index 1.","commonSituations":"Building command arguments dynamically and accidentally truncating them; using sendCommand with raw args instead of the typed API in cluster mode; off-by-one when slicing an argument array.","solutions":["Use the typed API (client.mSet, client.del) instead of sendCommand for compile-time argument validation","If using sendCommand, verify args.length is sufficient for the command's key region before sending","Add a defensive length check: for MSET ensure at least 2 args after the command name"],"exampleFix":"// before\nawait client.sendCommand(['MSET', 'key1']);\n// after\nawait client.mSet({ key1: 'value1' });","handlingStrategy":"validation","validationCode":"// For MSET-style flat arrays: ensure at least one key-value pair.\nfunction validateMSetArgs(args: unknown[]): void {\n  if (args.length < 2) {\n    throw new RangeError('MSET requires at least one key-value pair (2 args)');\n  }\n}","typeGuard":"function hasMinArgs(args: unknown[], min: number): boolean {\n  return Array.isArray(args) && args.length >= min;\n}","tryCatchPattern":null,"preventionTips":["Prefer typed APIs (client.mSet, client.mGet) over sendCommand for multi-key commands","Validate argument array length before passing to sendCommand","Use TypeScript to enforce non-empty tuple arrays at compile time"],"tags":["cluster","validation","arguments","multi-shard"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}