redis/node-redis · error · Error

Cannot split ${label}: unsupported find_keys range (lastkey

Error message

Cannot split ${label}: unsupported find_keys range (lastkey ${findKeys.lastKey}, limit ${findKeys.limit})

What it means

For `range` find_keys, the splitter only supports the 'until end of args' shape: lastKey === -1 and limit === 0. A bounded range (lastKey >= 0, i.e. keys occupy a fixed suffix region with trailing non-key args, or a non-zero limit/step pattern) is not implemented because no current multi_shard command needs it. The splitter refuses rather than mis-split.

Source

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

  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;
  let keyRegionStart: number;
  let keyRegionEnd: number;
  let keyStep: number;
  // Absolute position of the numkeys argument to rewrite per sub-command.
  let keyNumIdx: number | undefined;

  switch (findKeys.type) {
    case 'range': {
      // All current multi_shard range specs are "until end of args"; bounded
      // ranges (lastKey >= 0) and limit can be added when a command needs them.
      if (findKeys.lastKey !== -1 || findKeys.limit !== 0) {
        throw new Error(`Cannot split ${label}: unsupported find_keys range (lastkey ${findKeys.lastKey}, limit ${findKeys.limit})`);
      }
      keyStep = findKeys.keyStep;
      keyRegionStart = start;
      keyRegionEnd = args.length;
      break;
    }
    case 'keynum': {
      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;

View on GitHub (pinned to bb5beb5657)

Solutions

  1. Confirm the command's key region extends to end-of-args; if bounded, multi_shard split is not supported yet.
  2. Extend the range branch (multi-shard-splitter.ts:75) to handle bounded ranges if a real command needs it.
  3. Re-tag the command to default-keyed routing.
Defensive patterns

Strategy: try-catch

Type guard

function isUnboundedRange(spec: unknown): boolean {
  return typeof spec === 'object' && spec !== null
    && (spec as { type?: string }).type === 'range'
    && (spec as { lastKey?: number }).lastKey === -1
    && (spec as { limit?: number }).limit === 0;
}

Try / catch

try {
  await cluster.del('k1', 'k2');
} catch (e) {
  if (/unsupported find_keys range/.test(e.message)) {
    // spec is a bounded range — re-tag command or extend the splitter
  } else throw e;
}

Prevention

When it happens

Trigger: A command tagged multi_shard whose range spec has lastKey >= 0 or limit !== 0. Reachable only via metadata change; current commands (DEL/UNLINK/EXISTS/TOUCH/MGET/MSET) all use lastKey=-1, limit=0.

Common situations: A future multi_shard command whose keys occupy a bounded region followed by options; a metadata override mis-tagging such a command.

Related errors


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