redis/node-redis · error · Error

Unknown request policy

Error message

Unknown request policy ${requestPolicy}

What it means

Thrown in the cluster command dispatch when a command's resolved request policy is not present in the REQUEST_ROUTERS registry. The fast path (DEFAULT_KEYED) is handled earlier; this branch covers fan-out policies. An unknown policy means the command metadata or a custom command definition specified a request policy the cluster router does not know how to dispatch.

Solutions

  1. For custom commands, use a supported request policy (DEFAULT_KEYED, DEFAULT_KEYLESS, MULTI_SHARD, ALL_SHARDS, ALL_NODES, SPECIAL) or omit policy to get the default.
  2. Upgrade node-redis to a version whose policy table matches the command metadata you are using.
  3. Audit any code that sets command metadata .request to ensure it uses a value from REQUEST_POLICIES_WITH_DEFAULTS.
  4. Report with the command name and the resolved requestPolicy value if it occurs on a built-in command.

Example fix

// before (custom command metadata with bad policy)
{ REQUEST_POLICY: 'shard' /* misspelled, not in registry */ }

// after
{ REQUEST_POLICY: 'multi_shard' } // valid registry value
Defensive patterns

Strategy: validation

Validate before calling

import { REQUEST_POLICIES_WITH_DEFAULTS } from '@redis/client';
function isValidRequestPolicy(p: string): boolean {
  return Object.values(REQUEST_POLICIES_WITH_DEFAULTS).includes(p as never);
}
isValidRequestPolicy(metadata.request);

Type guard

function isKnownRequestPolicy(p: unknown, known: readonly string[]): p is string {
  return typeof p === 'string' && known.includes(p);
}

Try / catch

try {
  await cluster.executeCommand(...);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Unknown request policy')) {
    // fix command metadata to use a supported policy
  } else throw e;
}

Prevention

When it happens

Trigger: Defining a custom command (via sendCommand or a script) whose command metadata sets a request value not in REQUEST_POLICIES_WITH_DEFAULTS. A version mismatch where command metadata references a policy added in a newer release. Internal corruption of the policy registry.

Common situations: Using custom/script commands with manually-set policies that are misspelled or unsupported; running a command whose policy table entry was added after the installed library version; monkeypatching command metadata with an invalid request value.

Related errors


AI-assisted analysis of redis/node-redis@90fd0652bc (2026-08-11). Data as JSON: /api/errors/8beeeec685ad2b71. Report an issue: GitHub.

Appendix: source

Thrown at packages/client/lib/cluster/index.ts:570

    const responsePolicy = policy.response;

    // Fast path: default-keyed request + response — the overwhelming majority
    // of traffic (every single-key command). Route by firstKey and pass the
    // sole reply through, skipping the plan/reducer/post-reply machinery,
    // which is a no-op for this shape (the hooks only concern
    // FT.AGGREGATE/FT.CURSOR/SCAN and the remap only numeric aggregates —
    // none of them default-keyed).
    if (
      requestPolicy === REQUEST_POLICIES_WITH_DEFAULTS.DEFAULT_KEYED &&
      responsePolicy === RESPONSE_POLICIES_WITH_DEFAULTS.DEFAULT_KEYED
    ) {
      return this._execute(parser, readonly, options, makeFn(parser));
    }

    // https://redis.io/docs/latest/develop/reference/command-tips
    const router = REQUEST_ROUTERS[requestPolicy];
    if (!router) {
      throw new Error(`Unknown request policy ${requestPolicy}`);
    }
    // Validated before any per-node promise is dispatched — throwing after
    // would orphan in-flight rejections (unhandled-rejection noise) and run
    // side effects for a reply that can never be reduced.
    const reducer = RESPONSE_REDUCERS[responsePolicy];
    if (!reducer) {
      throw new Error(`Unknown response policy ${responsePolicy}`);
    }
    // Routers are typed against the erased base cluster types (routing is
    // below the typed command surface); bridge this instantiation's slots in.
    const plan = await router(
      this._slots as unknown as Parameters<typeof router>[0],
      parser,
      readonly,
      policy.keySpecs
    );

    if (plan.length === 0) {

View on GitHub (pinned to 90fd0652bc)