RESP Codec
What it is
TCP sends bytes, not complete messages. One read may contain part of a message or several messages. RESP is the message format used by Redis. A decoder must work no matter where the incoming chunks end.
The core idea
A streaming decoder remembers unfinished input across calls to Feed. A buffer makes this possible, but large unfinished messages can use a lot of memory. The decoder's progress matters as much as its stored bytes. RESP2 uses + for simple strings, - for errors, : for integers, $ for bulk strings, and * for arrays. Headers end with \r\n. Bulk strings declare a byte length, so their data may contain any bytes.
Example
Feed $5\r\nhel. No complete message is ready. Feed lo\r\n. Now return the bulk string hello. This must give the same message as feeding all the bytes together.
Where you meet this
- Redis: clients send every command as a RESP array of bulk strings, and the server answers with any RESP type. (RESP2 specification)
- Valkey uses the same protocol to talk to its clients. (Valkey protocol)
- Dragonfly says it is fully compatible with the Redis API, so Redis clients work without code changes. (Dragonfly docs)
When to choose it: a simple request and reply protocol where values can hold any bytes. Lengths come first, so the reader never scans the data for a special character and never needs escaping. The RESP spec says this makes it nearly as fast as a binary protocol while still easy to read.
When not to: both sides need a fixed schema with typed fields that is checked for them, or you want the smallest possible messages. A schema-based binary format fits better there.
Common bugs
- Losing unfinished bytes between calls.
- Returning only one message when several are ready.
- Looking for a line ending inside a bulk string instead of counting bytes.
- Treating empty and null strings as the same value.
- Accepting more input after a decoder error.
- Counting characters instead of bytes for UTF-8 data.
- Allocating all memory requested by a length before the data arrives.
Error rules
Follow the challenge page's error order and integer rules. A trailing \r alone may be unfinished, not invalid. Check array depth when a new array level opens. The 33rd level is too deep, even for an empty array.
Keep it fast
Resume from the saved position. Do not parse the whole input history again on every call.
Learn more
The Redis RESP specification explains the full message format. Networking texts explain why reads do not line up with messages.