This error occurs when a Redis client sends malformed commands or receives corrupted responses that violate the RESP (Redis Serialization Protocol) format. The issue typically stems from connection problems, protocol version mismatches, improper connection pooling, or network corruption. Fix by using connection pools, enabling proper authentication, ensuring RESP2/RESP3 compatibility, and validating command formatting.
Redis uses the RESP (Redis Serialization Protocol) to communicate between clients and servers. The "$" character marks the start of a bulk string in RESP format. When Redis receives a response that doesn't start with a valid type byte ($, +, -, :, or *), it throws this protocol error and disconnects the client. This error indicates that either your client sent a malformed command, the connection is corrupted, or there's a protocol version mismatch between the client library and Redis server. The error acts as a safety mechanism to prevent processing of invalid data and typically results in immediate connection termination.
The most common cause is creating a Jedis object directly and reusing it across multiple threads. This breaks RESP protocol synchronization. Always use a connection pool (JedisPool, Redis connection pool, etc.).
// WRONG - Do not reuse single connection
const redis = require('redis').createClient();
redis.get('key1', (err, data) => { /* ... */ });
redis.set('key2', 'value', (err) => { /* ... */ });
// CORRECT - Use connection pool
const { createPool } = require('generic-pool');
const redis = require('redis');
const pool = createPool({
create: async () => redis.createClient(),
destroy: async (client) => client.disconnect(),
}, { max: 10 });
const client = await pool.acquire();
try {
await client.get('key');
} finally {
await pool.release(client);
}For Java with Jedis:
// WRONG
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("key", "value");
// CORRECT
JedisPool pool = new JedisPool("localhost", 6379);
try (Jedis jedis = pool.getResource()) {
jedis.set("key", "value");
}If your Redis instance requires authentication, authenticate immediately after connecting, before sending any commands. Failing to authenticate causes the server to reject commands and close the connection.
// Using redis-cli
redis-cli -h host -p 6379
AUTH your-password
GET your-key
// Using Node.js redis client
const redis = require('redis');
const client = redis.createClient({
host: 'localhost',
port: 6379,
password: 'your-password'
});
client.on('error', (err) => console.error('Redis error:', err));
client.on('connect', () => console.log('Connected'));
// Or authenticate manually
client.auth('your-password', (err) => {
if (err) console.error('Auth failed:', err);
else client.get('key', (err, data) => { /* ... */ });
});# Using Python redis-py
import redis
r = redis.Redis(host='localhost', port=6379, password='your-password')
value = r.get('key')Some client libraries use RESP3 by default while older Redis servers only support RESP2. Ensure version compatibility or explicitly set the protocol version.
# Check Redis server protocol support
redis-cli HELLO 3
# Response shows supported protocol versions
# Force RESP2 in redis-cli if server doesn't support RESP3
redis-cli --no-rawFor Go redis client:
// Use RESP2 if server doesn't support RESP3
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Protocol: 2, // Force RESP2
})For Java Lettuce:
ClientOptions options = ClientOptions.builder()
.protocolVersion(ProtocolVersion.RESP2) // Use RESP2
.build();
RedisClient client = RedisClient.create();
client.setOptions(options);When sending commands via scripts or redis-cli --pipe, ensure proper RESP formatting with actual CRLF (\r\n) characters, not literal strings.
# WRONG - literal \r\n characters (will fail)
echo -e "SET mykey myvalue\\r\\n" | redis-cli --pipe
# CORRECT - actual CRLF
printf "*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n" | redis-cli --pipe
# Or use redis-benchmark to generate proper protocol
redis-benchmark -t set -n 100000 > commands.txt
redis-cli --pipe < commands.txtVerify connection stability:
# Test basic connectivity
redis-cli ping
# Test after multiple commands
redis-cli
> SET test1 value1
> GET test1
> SET test2 value2
> GET test2Protocol handling bugs are often fixed in newer versions. Update your Redis client library to the latest compatible version.
# Node.js
npm install redis@latest
npm install ioredis@latest
# Python
pip install --upgrade redis
# Java - Update in pom.xml
# Jedis
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.4.1</version>
</dependency>
# Lettuce
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.2</version>
</dependency>
# Go
go get -u github.com/redis/go-redis/v9Check library version compatibility with your Redis server version in the client documentation.
Enable protocol-level logging to see exactly what commands are being sent and what responses are received.
# redis-cli with verbose output
redis-cli -h localhost -p 6379 --debug
# Monitor all commands hitting Redis (in separate terminal)
redis-cli MONITOR
# Watch network packets with tcpdump
sudo tcpdump -i lo -A -s0 'tcp port 6379'For application-level debugging:
// Node.js redis client with debug mode
const redis = require('redis');
const client = redis.createClient({
host: 'localhost',
port: 6379,
debug: true,
retry_max_delay: 5000
});
client.on('error', (err) => {
console.error('Redis protocol error:', err);
console.error('Stack:', err.stack);
});# Python with verbose logging
import redis
import logging
logging.basicConfig(level=logging.DEBUG)
r = redis.Redis(decode_responses=True)
r.get('key')Use redis-benchmark to generate proper RESP commands and isolate whether the issue is in your application code or the Redis connection itself.
# Run basic performance test (validates connection and protocol)
redis-benchmark -h localhost -p 6379 -t set,get -q
# Test with specific payload sizes
redis-benchmark -h localhost -p 6379 -d 1024 -t get -q
# Test with pipelining (multiple commands per request)
redis-benchmark -h localhost -p 6379 -P 16 -q
# Output should show ops/sec without protocol errors
# If errors occur here, issue is with Redis or network, not your codeIf redis-benchmark succeeds but your application fails, the issue is in how your application formats or sends commands.
RESP Protocol Byte Format: Valid RESP responses always start with one of these type bytes:
- $ - Bulk String (e.g., $6\r\nfoobar\r\n)
- + - Simple String (e.g., +OK\r\n)
- - - Error (e.g., -ERR unknown command\r\n)
- : - Integer (e.g., :-1\r\n)
- * - Array (e.g., *2\r\n$6\r\nfoobar\r\n$3\r\nbaz\r\n)
If the first byte is anything else (especially null bytes, control characters, or garbage), the protocol is violated.
Connection Reuse Across Threads: In Java/Scala, using a single Jedis instance across threads will cause this error because RESP requires request/response pairs to be atomic per connection. One thread's response can be read by another thread, breaking protocol synchronization. Always use JedisPool.
Heroku Redis Limitations: Some managed Redis services (like Heroku) disconnect idle connections after 60 seconds. If a connection sits idle, the server closes it. The next command sent on that stale connection triggers a protocol error. Use connection pooling with reasonable timeouts and implement connection health checks.
Mass Import Protocol: When using redis-cli --pipe for bulk inserts, the format must be exact RESP. The file should contain complete RESP protocol messages. Use redis-benchmark -t set -n 1000000 | redis-cli --pipe to generate proper format.
Protocol Version Negotiation: When connecting, some clients may request a newer protocol version that the server doesn't support. If you see protocol errors immediately after connecting, try forcing RESP2 in your client configuration. Newer clients (Go redis 9+, ioredis, Lettuce 6+) use RESP3 by default.
ERR fsync error
How to fix "ERR fsync error" in Redis
CLUSTERDOWN The cluster is down
How to fix 'CLUSTERDOWN The cluster is down' in Redis
ERR Job for redis-server.service failed because a timeout was exceeded
Job for redis-server.service failed because a timeout was exceeded
ERR Unbalanced XREAD list of streams
How to fix "ERR Unbalanced XREAD list" in Redis
ERR syntax error
How to fix "ERR syntax error" in Redis