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

  1. Verify the command's keyStep in metadata is >= 1.
  2. Re-run metadata generation against a healthy Redis node.
  3. 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

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


AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03). Data as JSON: /data/errors/e12d0dc92cd7697e.json. Report an issue: GitHub.