redis/node-redis · error · Error
Cannot split ${label}: invalid keystep ${keyStep}
Error message
Cannot split ${label}: invalid keystep ${keyStep} What it means
splitMultiShardCommand requires keyStep >= 1 — keyStep is the stride between successive key groups (1 for DEL/MGET, 2 for MSET where each key is followed by its value). A keyStep < 1 is structurally invalid (zero or negative stride) and would produce infinite/overlapping groups, so the splitter refuses. This is a spec invariant; no real command declares keyStep < 1.
Source
Thrown at packages/client/lib/cluster/request-response-policies/multi-shard-splitter.ts:102
keyStep = findKeys.keyStep;
keyNumIdx = start + findKeys.keyNumIdx;
keyRegionStart = start + findKeys.firstKey;
if (keyNumIdx >= keyRegionStart) {
throw new Error(`Cannot split ${label}: numkeys argument inside the key region`);
}
const numKeys = parsePositiveInteger(args[keyNumIdx]);
if (numKeys === undefined) {
throw new Error(`Cannot split ${label}: malformed numkeys argument '${args[keyNumIdx]}'`);
}
keyRegionEnd = keyRegionStart + numKeys * keyStep;
break;
}
default:
throw new Error(`Cannot split ${label}: unsupported find_keys type '${findKeys.type}'`);
}
if (keyStep < 1) {
throw new Error(`Cannot split ${label}: invalid keystep ${keyStep}`);
}
if (keyRegionStart < 1 || keyRegionEnd > args.length) {
throw new Error(`Cannot split ${label}: key region overruns the arguments`);
}
const regionLength = keyRegionEnd - keyRegionStart;
if (regionLength <= 0 || regionLength % keyStep !== 0) {
throw new Error(`Cannot split ${label}: key region does not align with keystep ${keyStep}`);
}
const groupCount = regionLength / keyStep;
const slotGroups = new Map<number, Array<number>>();
for (let group = 0; group < groupCount; group++) {
const slot = calculateSlot(args[keyRegionStart + group * keyStep]);
const groups = slotGroups.get(slot);
if (groups) {
groups.push(group);
} else {
slotGroups.set(slot, [group]);View on GitHub (pinned to bb5beb5657)
Solutions
- Verify the command's keyStep in metadata is >= 1.
- Re-run metadata generation against a healthy Redis node.
- Re-tag the command to default-keyed routing if the spec is unusable.
Defensive patterns
Strategy: try-catch
Type guard
function isValidKeyStep(spec: unknown): boolean {
return typeof spec === 'object' && spec !== null && typeof (spec as { keyStep?: number }).keyStep === 'number' && (spec as { keyStep?: number }).keyStep! >= 1;
} Try / catch
try {
await cluster.del('k1', 'k2');
} catch (e) {
if (/invalid keystep/.test(e.message)) {
// metadata reports keyStep < 1 — regenerate or override
} else throw e;
} Prevention
- Verify the command's keyStep in metadata is >= 1.
- Re-run metadata generation against a healthy Redis node.
- Re-tag commands with unusable specs to default-keyed routing.
When it happens
Trigger: A command tagged multi_shard whose spec reports keyStep < 1. Reachable only via malformed metadata or a future spec; not user-argument-triggered.
Common situations: A metadata corruption/regeneration producing a zero/negative keyStep; an exotic future spec.
Related errors
- Cannot split ${label}: command has no key specification
- Cannot split ${label}: multiple key specifications are not s
- Cannot split ${label}: unsupported begin_search type '${begi
- Cannot split ${label}: unsupported find_keys range (lastkey
- Cannot split ${label}: numkeys argument inside the key regio
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/e12d0dc92cd7697e.json.
Report an issue: GitHub.