redis/node-redis · error · Error

Cannot split : command has no key specification

Error message

Cannot split ${label}: command has no key specification

What it means

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.

Solutions

  1. Run COMMAND INFO <command> on the cluster to verify key specs are reported by the server
  2. If the command genuinely has no keys, it should not be tagged multi_shard — check metadata overrides
  3. Report the issue if a standard command (DEL, EXISTS, MGET, MSET, TOUCH, UNLINK) triggers this, as all have key specs in the static metadata
Defensive patterns

Strategy: try-catch

Type guard

function isNoKeySpec(err: unknown): boolean {
  return err instanceof Error && err.message.includes('no key specification');
}

Try / catch

try {
  await cluster.del('key1', 'key2');
} catch (err) {
  if (err instanceof Error && err.message.includes('no key specification')) {
    // metadata issue — fall back to per-slot manual routing
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11). Data as JSON: /api/errors/271d686230926548. Report an issue: GitHub.

Appendix: source

Thrown at packages/client/lib/cluster/request-response-policies/multi-shard-splitter.ts:46

 * relative order) + suffix; for `keynum` specs the numkeys argument in the
 * prefix is rewritten to the sub-command's group count.
 *
 * Throws on anything it cannot split deterministically — a wrong split of a
 * write command means corrupted data, so refusal beats guessing. All current
 * multi_shard commands (DEL, UNLINK, EXISTS, TOUCH, MGET, MSET) declare
 * exactly one supported spec. MSETEX is curated OUT of multi_shard
 * (command-metadata-overrides.ts): its NX/XX condition is all-or-nothing
 * across all keys and cannot be evaluated per shard — it routes default-keyed
 * like MSETNX, so the keynum branch below currently has no live caller.
 */
export function splitMultiShardCommand(
  args: ReadonlyArray<RedisArgument>,
  keySpecs: ReadonlyArray<KeySpec> | undefined
): Map<number, SubCommand> {
  const label = args.length > 0 ? args[0].toString() : '<empty>';

  if (!keySpecs || keySpecs.length === 0) {
    throw new Error(`Cannot split ${label}: command has no key specification`);
  }
  // TODO(multi-spec): a command whose keys are interchangeable but
  // syntactically scattered (e.g. a fixed-position key plus a keyword-tail
  // list) could legitimately be multi_shard with several specs, and
  // multi-region reconstruction would be deterministic. No such command
  // exists, and specs alone cannot distinguish that shape from linked-operand
  // specs (GEORADIUS-like) where splitting is meaningless — so refuse until a
  // real command motivates multi-region support.
  if (keySpecs.length > 1) {
    throw new Error(`Cannot split ${label}: multiple key specifications are not supported`);
  }

  const { beginSearch, findKeys } = keySpecs[0];
  if (beginSearch.type !== 'index') {
    throw new Error(`Cannot split ${label}: unsupported begin_search type '${beginSearch.type}'`);
  }

  const start = beginSearch.index;

View on GitHub (pinned to 90fd0652bc)