{"id":"ec8c47685176c140","repo":"redis/node-redis","slug":"cannot-split-label-malformed-numkeys-argument","errorCode":null,"errorMessage":"Cannot split ${label}: malformed numkeys argument '${args[keyNumIdx]}'","messagePattern":"Cannot split (.+?): malformed numkeys argument '(.+?)'","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/client/lib/cluster/request-response-policies/multi-shard-splitter.ts","lineNumber":92,"sourceCode":"      // ranges (lastKey >= 0) and limit can be added when a command needs them.\n      if (findKeys.lastKey !== -1 || findKeys.limit !== 0) {\n        throw new Error(`Cannot split ${label}: unsupported find_keys range (lastkey ${findKeys.lastKey}, limit ${findKeys.limit})`);\n      }\n      keyStep = findKeys.keyStep;\n      keyRegionStart = start;\n      keyRegionEnd = args.length;\n      break;\n    }\n    case 'keynum': {\n      keyStep = findKeys.keyStep;\n      keyNumIdx = start + findKeys.keyNumIdx;\n      keyRegionStart = start + findKeys.firstKey;\n      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  }","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/redis/node-redis/blob/bb5beb56578573910e2ee8f39681edc214c41398/packages/client/lib/cluster/request-response-policies/multi-shard-splitter.ts#L74-L110","documentation":"For `keynum` specs, the numkeys argument read from the command args must be a positive integer. A non-integer, zero, negative, or non-numeric value (e.g. 'abc', '2.5', '0', '') cannot be used to compute the key region, so the splitter refuses with the offending value in the message. Unlike most splitter errors, this is a USER-ARGUMENT error: the caller passed a bad numkeys.","triggerScenarios":"Issuing a keynum-spec multi_shard command (e.g. a hypothetical MSETEX) with a numkeys argument that is not a positive integer. Note: MSEDEX is currently curated OUT of multi_shard (routes default-keyed like MSETNX), so the keynum branch has no live caller in the shipped metadata — this fires only if a keynum-spec command is re-enabled or added.","commonSituations":"A raw sendCommand with a wrong numkeys; a future keynum multi_shard command where the caller mis-counts keys; a buffer/whitespace numkeys argument.","solutions":["Pass a valid positive integer for the numkeys argument matching the number of key groups you provide.","Use the typed command API rather than raw sendCommand so argument validation happens before routing.","If using a keynum command, ensure numkeys exactly equals the trailing key/value groups."],"exampleFix":"// before\nawait cluster.sendCommand(['MSEDEX', 'abc', '{a}1', 'v1', 'NX', 'EX', '10']);\n// throws: Cannot split MSEDEX: malformed numkeys argument 'abc'\n\n// after — numkeys is a positive integer matching the key groups\nawait cluster.sendCommand(['MSEDEX', '1', '{a}1', 'v1', 'NX', 'EX', '10']);","handlingStrategy":"validation","validationCode":"// Validate numkeys before issuing a keynum-spec multi_shard command.\nfunction assertValidNumkeys(numkeys: unknown): asserts numkeys is number {\n  const n = Number(numkeys);\n  if (!Number.isInteger(n) || n <= 0) {\n    throw new TypeError(`numkeys must be a positive integer, got ${JSON.stringify(numkeys)}`);\n  }\n}\nassertValidNumkeys(process.argv[2]);\nawait cluster.sendCommand(['MSEDEX', String(numkeys), ...keyGroups, 'NX', 'EX', '10']);","typeGuard":"function isPositiveInteger(value: unknown): value is number {\n  return Number.isInteger(Number(value)) && Number(value) > 0;\n}","tryCatchPattern":"try {\n  await cluster.sendCommand(['MSEDEX', numkeys, ...keyGroups, 'NX', 'EX', '10']);\n} catch (e) {\n  if (/malformed numkeys/.test(e.message)) {\n    // caller passed a bad numkeys — fix the argument\n  } else throw e;\n}","preventionTips":["Pass a positive integer for numkeys matching the number of key groups supplied.","Prefer the typed command API over raw sendCommand so arg validation happens before routing.","Compute numkeys from the actual key array length rather than hardcoding it."],"tags":["cluster","multi-shard","keynum","user-input","splitter"],"analyzedSha":"bb5beb56578573910e2ee8f39681edc214c41398","analyzedAt":"2026-08-03T19:09:15.686Z","schemaVersion":2}