redis/node-redis · error · TypeError
"arguments[${i}]" must be of type "string | Buffer", got ${t
Error message
"arguments[${i}]" must be of type "string | Buffer", got ${typeof arg} instead. What it means
Thrown by the RESP command encoder (encodeCommand) when iterating over command arguments: every arg must be either a string or a Buffer so it can be length-prefixed and written to the wire. If any element is a number, boolean, object, null, or undefined, the encoder cannot compute its byte length and rejects it with a TypeError naming the offending index and the actual typeof. This guards the lowest layer of the client against emitting malformed RESP.
Source
Thrown at packages/client/lib/RESP/encoder.ts:21
const CRLF = '\r\n';
export default function encodeCommand(args: ReadonlyArray<RedisArgument>): ReadonlyArray<RedisArgument> {
const toWrite: Array<RedisArgument> = [];
let strings = '*' + args.length + CRLF;
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (typeof arg === 'string') {
strings += '$' + Buffer.byteLength(arg) + CRLF + arg + CRLF;
} else if (arg instanceof Buffer) {
toWrite.push(
strings + '$' + arg.length.toString() + CRLF,
arg
);
strings = CRLF;
} else {
throw new TypeError(`"arguments[${i}]" must be of type "string | Buffer", got ${typeof arg} instead.`);
}
}
toWrite.push(strings);
return toWrite;
}
View on GitHub (pinned to bb5beb5657)
Solutions
- Coerce each dynamic argument to a string before passing it: `String(value)` or `Buffer.from(value)`.
- If the value is binary, pass it as a Buffer: `Buffer.from(value)`.
- For custom commands, ensure parseCommand only ever pushes string/Buffer via parser.push / parser.pushVariadic with pre-converted values.
- Validate/serialize at the boundary where untrusted JSON enters your Redis call layer.
Example fix
// before await client.sendCommand(['SET', 'counter', 123]); // after await client.sendCommand(['SET', 'counter', String(123)]);
Defensive patterns
Strategy: validation
Validate before calling
function toRedisArg(value: unknown): string | Buffer {
if (typeof value === 'string') return value;
if (Buffer.isBuffer(value)) return value;
throw new TypeError(`Cannot encode ${typeof value} as a Redis argument`);
}
// usage: client.sendCommand(['SET', 'k', toRedisArg(maybeNumber) as string]); Type guard
function isRedisArgument(arg: unknown): arg is string | Buffer {
return typeof arg === 'string' || Buffer.isBuffer(arg);
} Try / catch
try {
await client.sendCommand(args);
} catch (err) {
if (err instanceof TypeError && /must be of type/.test(err.message)) {
// an argument was not string|Buffer; serialize and retry, or surface a config error
}
throw err;
} Prevention
- Never pass numbers/booleans/objects/raw JSON into command args without explicit String()/Buffer conversion.
- Type your command-building helpers to accept only string | Buffer.
- Enable strict TypeScript types so untyped values cannot reach sendCommand.
When it happens
Trigger: Calling `client.sendCommand([42])` or `client.set('k', 123)` where 123 is a number (some commands coerce, but raw sendCommand and custom commands do not). Passing an object/undefined/null as a command argument, or using `client.multi().addCommand(['GET', someObject])`. Building args from untyped JSON without stringifying numeric/boolean fields.
Common situations: Passing numeric counters/IDs straight from JS logic into a command; forgetting to `String()` or `.toString()` values read from JSON/env; mixing a loosely-typed data layer with the strongly-typed Redis client; writing a custom Command whose parseCommand pushes a non-coerced variable.
Related errors
- expirationRefreshRatio must be less than or equal to 1
- expirationRefreshRatio must be greater or equal to 0
- All statistics values must be non-negative
- HIMPORT PREPARE/DISCARD/DISCARDALL are not supported inside
- tls socket option is set to ${options.socket.tls} which is m
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/3fdd5bd1b3b5842d.json.
Report an issue: GitHub.