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
- 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
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
- 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
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
- Cannot split : malformed numkeys argument
- Cannot split : multiple key specifications are not supported
- Cannot split : numkeys argument inside the key region
- Cannot split : unsupported begin_search type
- Cannot split : unsupported find_keys range (lastkey , limit…
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)