{"record":{"id":"271d686230926548","repo":"redis/node-redis","slug":"cannot-split-label-command-has-no-key-specific","errorCode":null,"errorMessage":"Cannot split ${label}: command has no key specification","messagePattern":"Cannot split (.+?): command has no key specification","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/client/lib/cluster/request-response-policies/multi-shard-splitter.ts","lineNumber":46,"sourceCode":" * relative order) + suffix; for `keynum` specs the numkeys argument in the\n * prefix is rewritten to the sub-command's group count.\n *\n * Throws on anything it cannot split deterministically — a wrong split of a\n * write command means corrupted data, so refusal beats guessing. All current\n * multi_shard commands (DEL, UNLINK, EXISTS, TOUCH, MGET, MSET) declare\n * exactly one supported spec. MSETEX is curated OUT of multi_shard\n * (command-metadata-overrides.ts): its NX/XX condition is all-or-nothing\n * across all keys and cannot be evaluated per shard — it routes default-keyed\n * like MSETNX, so the keynum branch below currently has no live caller.\n */\nexport function splitMultiShardCommand(\n  args: ReadonlyArray<RedisArgument>,\n  keySpecs: ReadonlyArray<KeySpec> | undefined\n): Map<number, SubCommand> {\n  const label = args.length > 0 ? args[0].toString() : '<empty>';\n\n  if (!keySpecs || keySpecs.length === 0) {\n    throw new Error(`Cannot split ${label}: command has no key specification`);\n  }\n  // TODO(multi-spec): a command whose keys are interchangeable but\n  // syntactically scattered (e.g. a fixed-position key plus a keyword-tail\n  // list) could legitimately be multi_shard with several specs, and\n  // multi-region reconstruction would be deterministic. No such command\n  // exists, and specs alone cannot distinguish that shape from linked-operand\n  // specs (GEORADIUS-like) where splitting is meaningless — so refuse until a\n  // real command motivates multi-region support.\n  if (keySpecs.length > 1) {\n    throw new Error(`Cannot split ${label}: multiple key specifications are not supported`);\n  }\n\n  const { beginSearch, findKeys } = keySpecs[0];\n  if (beginSearch.type !== 'index') {\n    throw new Error(`Cannot split ${label}: unsupported begin_search type '${beginSearch.type}'`);\n  }\n\n  const start = beginSearch.index;","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/client/lib/cluster/request-response-policies/multi-shard-splitter.ts#L28-L64","documentation":"Thrown by the multi-shard splitter when a command tagged multi_shard has no COMMAND key specification (keySpecs is undefined or empty). The splitter uses key specs to locate keys in the argument list and group them by hash slot; without specs, it cannot determine where keys are and refuses to split rather than risk corrupting a write command.","triggerScenarios":"A command is tagged multi_shard in the metadata but its COMMAND DOCS/INFO response provides no key specs; a custom command routed as multi_shard without key specs; the Redis server version doesn't report key specs for this command.","commonSituations":"Metadata corruption or stale metadata; dynamic COMMAND DOCS resolution from a server that omits key specs; custom command definitions that set multi_shard without providing key specs.","solutions":["Run COMMAND INFO <command> on the cluster to verify key specs are reported by the server","If the command genuinely has no keys, it should not be tagged multi_shard — check metadata overrides","Report the issue if a standard command (DEL, EXISTS, MGET, MSET, TOUCH, UNLINK) triggers this, as all have key specs in the static metadata"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isNoKeySpec(err: unknown): boolean {\n  return err instanceof Error && err.message.includes('no key specification');\n}","tryCatchPattern":"try {\n  await cluster.del('key1', 'key2');\n} catch (err) {\n  if (err instanceof Error && err.message.includes('no key specification')) {\n    // metadata issue — fall back to per-slot manual routing\n  } else {\n    throw err;\n  }\n}","preventionTips":["Verify COMMAND INFO for the command shows key specs on the server","All standard multi_shard commands (DEL, EXISTS, MGET, MSET, TOUCH, UNLINK) have key specs — report if one triggers this","Do not manually tag commands as multi_shard without providing key specs in metadata"],"tags":["cluster","multi-shard","key-spec","metadata"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}