redis/node-redis · critical · Error

Cannot split ${label}: key region does not align with keyste

Error message

Cannot split ${label}: key region does not align with keystep ${keyStep}

What it means

Thrown by splitMultiShardCommand when the cluster client tries to fan out a multi-shard command (DEL, UNLINK, EXISTS, TOUCH, MGET, MSET) but the argument region containing key/value groups is not a whole multiple of the command's keyStep. The splitter refuses to guess because a wrong split of a write command silently corrupts data, so this is a hard invariant violation in the command's declared key specification versus the actual argument array.

Source

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

      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]);
    }
  }

  const subCommands = new Map<number, SubCommand>();

  // Single-slot fast path: nothing to split — pass the original command
  // through untouched (also preserves single-slot atomicity). Keys keep their

View on GitHub (pinned to bb5beb5657)

Solutions

  1. Upgrade @redis/client to the latest patch release — this is an internal invariant mismatch, likely already fixed against the server's current COMMAND reply.
  2. Capture the exact command name and argument array (args[0]) from the error label and file a bug against node-redis with the Redis server version and command involved.
  3. If you trigger it via a custom command/sendCommand path, verify the argument count matches the command's documented arity before sending.
  4. As a workaround, disable multi_shard routing for that command or issue the operation as separate single-key commands.

Example fix

// before: relies on multi_shard split of a command whose metadata is wrong
await cluster.mset(['k1', 'v1', 'k2']); // odd trailing arg count after key region

// after: pass complete key/value groups so the region aligns with keyStep 2
await cluster.mset(['k1', 'v1', 'k2', 'v2']);
Defensive patterns

Strategy: try-catch

Validate before calling

// No caller-side validation possible: the mismatch is between command metadata
// and the args array produced internally. Validate arity before sending if you
// build args manually:
function assertEvenKvPairs(args) {
  if (args.length < 2 || (args.length % 2) !== 0) throw new TypeError('expected even key/value count');
}

Type guard

// Guards that a flat array is complete key/value pairs for keyStep-2 commands.
function isAlignedKvArray(arr) { return Array.isArray(arr) && arr.length > 0 && arr.length % 2 === 0; }

Try / catch

try { await cluster.mset(pairs); } catch (e) { if (/does not align with keystep/.test(e.message)) { /* metadata/arity bug — report, fall back to per-key SET */ for (const [k,v] of chunk(pairs,2)) await cluster.set(k,v); } else throw e; }

Prevention

When it happens

Trigger: Reached only on the internal routing path of cluster multi_shard commands. Triggered when (keyRegionEnd - keyRegionStart) % keyStep !== 0, e.g. MSET invoked with an odd number of trailing args after the command name and key region start, or a command whose COMMAND key spec (beginSearch.index / findKeys.keyStep) disagrees with the real arity of the args array passed in.

Common situations: Almost always indicates a bug in the command metadata (keySpecs) shipped with the client, or an arguments array that was mutated/truncated after command parsing. Can surface after upgrading the client or Redis server if a command's COMMAND DOCS key specification changed. Not something end users construct directly via the public API.

Related errors


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