redis/node-redis · error · MultiErrorReply
${errorIndexes.length} commands failed, see .replies and .er
Error message
${errorIndexes.length} commands failed, see .replies and .errorIndexes for more information What it means
A MultiErrorReply thrown by RedisMultiCommand.transformReplies after a MULTI/EXEC (or pipeline) batch where at least one individual reply is an ErrorReply. It bundles every reply and the indexes that failed so callers can inspect which commands errored without losing the successful ones. The thrown object exposes .replies, .errorIndexes, and an .errors() generator.
Source
Thrown at packages/client/lib/multi-command.ts:74
redisArgs.push(...args);
this.addCommand(redisArgs, transformReply);
}
transformReplies(rawReplies: Array<unknown>): Array<unknown> {
const errorIndexes: Array<number> = [],
replies = rawReplies.map((reply, i) => {
if (reply instanceof ErrorReply) {
errorIndexes.push(i);
return reply;
}
const { transformReply, args } = this.queue[i];
return transformReply ? transformReply(reply, args.preserve, this.typeMapping) : reply;
});
if (errorIndexes.length) throw new MultiErrorReply(replies, errorIndexes);
return replies;
}
}
View on GitHub (pinned to bb5beb5657)
Solutions
- Catch the error and iterate err.errorIndexes / err.errors() to see which commands failed and why.
- Fix the individual command that produced the ErrorReply (read err.replies[i].message for the underlying cause).
- If partial success is acceptable, read err.replies for the non-error slots and proceed.
- Separate risky commands into their own transaction to isolate failures.
Example fix
// before
const replies = await multi.get('k1').set('k2','v2').exec();
// after
try {
const replies = await multi.get('k1').set('k2','v2').exec();
} catch (e) {
if (e.errorIndexes) {
for (const [i, err] of e.errors()) console.error(`cmd #${i}:`, err.message);
const ok = e.replies.filter((_, idx) => !e.errorIndexes.includes(idx));
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Cannot validate server-side command outcomes ahead of exec(). Validate inputs // (types, arity) per queued command to reduce failures.
Type guard
function isMultiErrorReply(e) { return e instanceof Error && Array.isArray(e.errorIndexes) && Array.isArray(e.replies); } Try / catch
try { return await multi.exec(); } catch (e) { if (isMultiErrorReply(e)) { for (const [i, err] of e.errors()) log(`#${i}`, err.message); return e.replies; } throw e; } Prevention
- Validate each queued command's key types/arity before exec.
- Inspect err.errorIndexes and err.errors() to localize failures.
- Isolate risky commands in their own transaction to avoid poisoning the batch.
When it happens
Trigger: Executing multi.exec(true) (typed/generic mode) where one queued command produced a server-side ErrorReply — e.g. a type error, WRONGTYPE, arity error, or a WATCH conditional abort (EXECABORT surfaces differently). Any pipeline/multi whose raw replies include Error instances.
Common situations: Batching heterogeneous commands where one key has the wrong type; a LUA script error in one slot of the pipeline; optimistic concurrency with WATCH where individual commands reject; one malformed command in a bulk batch.
Related errors
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/cd9e30c81091ebe2.json.
Report an issue: GitHub.