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
- Read the wrapped err.message in the 500 response; it names the underlying cause to fix.
- Validate command arguments are all JSON-encodable primitives before POSTing.
- Check for null elements in the command array — these throw before the 403 channel.
- 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
- Validate every command element is a primitive before sending
- Avoid null/undefined elements in command arrays
- Keep the node-redis major version pinned to what the proxy's transaction chain expects
- Log the full failing command when a 500 comes back to speed diagnosis
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
- Malformed command: expected an array whose first element is…
- Redis HTTP
- Redis transaction failed: HTTP
- Widget body too large
- Airport delay filters are not supported
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 anView on GitHub (pinned to e586b8b4b8)