redis/node-redis · critical · Error

Unknown RESP type

Error message

Unknown RESP type ${type} "${String.fromCharCode(type)}"

What it means

Thrown from the default branch of the RESP3 decoder's top-level decodeReply switch. Every well-formed reply must start with a known type byte (NULL, BOOLEAN, NUMBER, DOUBLE, BIG_NUMBER, SIMPLE_STRING, BLOB_STRING, VERBATIM_STRING, SIMPLE_ERROR, BLOB_ERROR, ARRAY, SET, MAP, PUSH). An unrecognized leading byte means the byte stream is not valid RESP3 at the reply boundary. The message prints both the numeric code and its ASCII char for diagnostics.

Solutions

  1. Verify the endpoint is a real Redis: redis-cli -h <host> -p <port> PING.
  2. Stop forcing RESP: 3 in options; let the client negotiate the highest mutually supported version.
  3. Confirm TLS settings (socket.tls / rediss://) match the server's actual mode.
  4. If the byte is consistent and reproducible, capture it and file a client bug with the command that triggered it.

Example fix

// before
const client = createClient({ url: 'redis://...', RESP: 3 });

// after
const client = createClient({ url: 'redis://...' }); // let the client negotiate RESP version
Defensive patterns

Strategy: try-catch

Validate before calling

import { createClient } from 'redis';

async function assertRedisEndpoint(url) {
  const probe = createClient({ url });
  probe.on('error', () => {});
  await probe.connect();
  const pong = await probe.ping();
  await probe.disconnect();
  if (pong !== 'PONG') throw new Error(`endpoint ${url} did not PONG`);
}

await assertRedisEndpoint('redis://host:6379');

Try / catch

const client = createClient({ url });
client.on('error', err => {
  if (/Unknown RESP type/.test(err.message)) {
    console.error('Stream desync detected; reconnecting', err);
  }
});
try {
  await client.connect();
} catch (err) {
  // surface protocol mismatch before the app runs commands
  throw err;
}

Prevention

When it happens

Trigger: Connecting the client (RESP3 mode) to something that is not a Redis server; a proxy injecting non-RESP bytes; RESP2-only server where the HELLO/3 negotiation left the stream misaligned; truncated or corrupted reply mid-frame; TLS plaintext/encrypted mismatch producing garbage.

Common situations: Pointing the url at a wrong service port (e.g. an HTTP or stats endpoint); HAProxy/nginx misroute; rediss:// against a plaintext port or vice-versa; redis server older than 6.0 with RESP forced to 3; a custom command whose reply shape the decoder cannot parse.

Related errors


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

Appendix: source

Thrown at packages/client/lib/RESP/decoder.ts:234

        return this.#handleDecodedValue(
          this.onReply,
          this.#decodeSet(this.getTypeMapping(), chunk)
        );

      case RESP_TYPES.MAP:
        return this.#handleDecodedValue(
          this.onReply,
          this.#decodeMap(this.getTypeMapping(), chunk)
        );

      case RESP_TYPES.PUSH:
        return this.#handleDecodedValue(
          this.onPush,
          this.#decodeArray(PUSH_TYPE_MAPPING, chunk)
        );

      default:
        throw new Error(`Unknown RESP type ${type} "${String.fromCharCode(type)}"`);
    }
  }

  #handleDecodedValue(cb, value) {
    if (typeof value === 'function') {
      this.#next = this.#continueDecodeValue.bind(this, cb, value);
      return true;
    }

    cb(value);
    return false;
  }

  #continueDecodeValue(cb, next, chunk) {
    this.#next = undefined;
    return this.#handleDecodedValue(cb, next(chunk));
  }

View on GitHub (pinned to 90fd0652bc)