koala73/worldmonitor · error

${err.message}

Error message

${err.message}

What it means

When queueing a command for execution, the proxy catches errors from commandForExecution and re-throws any error lacking the commandNotAllowed flag, letting respondError turn it into a 500 with the error's message. So this message is the raw text of whatever non-authorization failure occurred while building/queueing the command (e.g. the malformed-command TypeError from assertCommandAllowed propagating, or a queue/serialization failure).

Solutions

  1. Read the wrapped err.message in the 500 response; it names the underlying cause to fix.
  2. Validate command arguments are all JSON-encodable primitives before POSTing.
  3. Check for null elements in the command array — these throw before the 403 channel.
  4. Verify the node-redis version matches the transaction API the proxy expects (addCommand on the v4 chain).

Example fix

// before
const args = ['SET', 'k', null]; // null element -> 500
// after
const args = ['SET', 'k', 'value'];
Defensive patterns

Strategy: try-catch

Validate before calling

if (args.some((a) => a === null || a === undefined || typeof a === 'object')) throw new Error('command args must be JSON primitives');

Type guard

const isQueueable = (args) => Array.isArray(args) && args.every((a) => ['string','number','boolean'].includes(typeof a));

Try / catch

const res = await proxyCommand(args);
if (res.status === 500) { const { error } = await res.json(); console.error('command queueing failed:', error); /* fix args and retry */ }

Prevention

When it happens

Trigger: Any exception thrown by commandForExecution that is not flagged commandNotAllowed: malformed command structures slipping past earlier checks, protocol/encoding problems in the queued command, or internal redis client errors during addCommand.

Common situations: Commands with wrong element types (nulls/objects as arguments) that pass the first-element check but fail later validation; client bugs in building multi-element commands; redis client version mismatches in the transaction chain.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22). Data as JSON: /api/errors/9a4430042390f700. Report an issue: GitHub.

Appendix: source

Thrown at docker/redis-rest-proxy.mjs:952

      const multi = client.multi();
      for (const cmd of commands) {
        // 403 means one thing: the gate refused this command. It used to mean
        // "something threw somewhere in here" — the try wrapped the queueing
        // call too, so the TypeError below was reported to operators as an
        // authorization failure, and #8265 read as a misconfigured REDIS_TOKEN
        // for as long as it did.
        //
        // Narrowing the try is not enough on its own: commandForExecution
        // itself throws a TypeError, not a gate rejection, when a body element
        // is null or undefined (`String(args[0])`). Keying on the tag rather
        // than on "this line threw" is what keeps a malformed body out of the
        // 403 channel. Everything untagged falls through to respondError().
        let queuedCommand;
        try {
          queuedCommand = commandForExecution(cmd);
        } catch (err) {
          if (!err?.commandNotAllowed) throw err;
          res.writeHead(403);
          res.end(JSON.stringify({ error: err.message }));
          return;
        }
        // addCommand, not sendCommand: sendCommand is a method on the node-redis
        // CLIENT, and the v4 transaction chain (redis@4, per
        // docker/Dockerfile.redis-rest) queues raw commands with addCommand. The
        // wrong one made every /multi-exec fail, so both seeders that publish
        // exclusively through it — seed-fred-rates, seed-bis-extended — never
        // wrote a key on a self-hosted install (#8265).
        multi.addCommand(queuedCommand);
      }
      // exec() rejects two different ways, and only one of them is a response
      // rather than a failure. Both were unreachable until #8265 was fixed —
      // nothing was ever queued — so neither has run in production.
      //
      // MultiErrorReply means the transaction RAN and some commands replied
      // with an error; node-redis hides the ordered replies on err.replies
      // instead of returning them. Upstash answers that with HTTP 200 and an

View on GitHub (pinned to e586b8b4b8)