Fixed header (4 bytes)
Version (2b), Type (2b), Token Length (4b), Code (8b), Message ID (16b). Always present, always this size.
Suppose a client asks for /sensors/temp, but the server returns 4.02 Bad Option. The useful question is not “is CoAP broken?” It is whether the decoder walked the bytes in the same order the sender encoded them: fixed header, token, option delta, option length, option value, payload marker, payload.
Use this page as the trace-reading pass. The goal is to make every nibble explainable before a firmware bug, proxy bug, or malformed request can hide behind a generic error code.
After this page, you should be able to:
CoAP Message Format introduces the compact message layout and shows how fixed headers, tokens, options, and payloads fit together. This page narrows in on the byte-level parsing rules that make that layout unambiguous in packet captures and protocol implementations.
The CoAP message parser follows one repeatable order: fixed header, Token, sorted options, optional payload marker, and payload bytes.
Use it when a decoder has an off-by-token-length bug, a capture shows a mysterious 4.02 Bad Option, a proxy misreads Uri-Path segments, or a payload is being interpreted as more options because the 0xFF marker is missing.
Every CoAP message starts with the same 4-byte fixed header. Reading left to right, it packs a 2-bit Version (currently 1), a 2-bit Type (CON, NON, ACK, or RST), a 4-bit Token Length (TKL, 0 to 8), an 8-bit Code, and a 16-bit Message ID. After those four bytes comes the Token (exactly TKL bytes), then zero or more Options, and finally — only if there is a payload — a single 0xFF marker byte followed by the payload.
The Code byte is the hinge of the whole format. It is split into a 3-bit class and a 5-bit detail, written as class.detail. Class 0 marks a request (0.01 GET, 0.02 POST, 0.03 PUT, 0.04 DELETE); classes 2, 4, and 5 mark responses (2.05 Content, 4.04 Not Found, 5.00 Internal Server Error). One byte tells a parser whether it is looking at a request or a response and what happened.
A fast sanity check is to decode the first byte before reading anything else. If the first byte is 0x44, its bits are 01 00 0100: Version 1, Confirmable, and a 4-byte Token. The parser then knows the next four bytes after the fixed header belong to the Token, not to Options. That single decision prevents the common off-by-four error where a decoder treats token bytes as Uri-Path option bytes and reports a nonsense resource.
The whole fixed header is four bytes. Compare that with an HTTP request line plus headers, which is typically hundreds of bytes of ASCII. That compactness is the reason CoAP fits in a single UDP datagram on a constrained link.
Version (2b), Type (2b), Token Length (4b), Code (8b), Message ID (16b). Always present, always this size.
Length equals TKL. Correlates a response with its request, independent of the Message ID.
Ordered, delta-encoded type-length-value fields carrying URI, content format, caching, and more.
A single 0xFF byte separates options from payload. No marker means no payload.
CoAP does not carry named text headers. It carries Options: numbered type-length-value fields sorted by their option number. Each option is written relative to the previous one. A one-byte prefix holds a 4-bit option delta (the increase in option number since the last option) and a 4-bit length. When a delta or length exceeds 12, an extension follows: the nibble value 13 means "add one extended byte," 14 means "add a two-byte extension," and 15 is reserved — a full byte of 0xFF is the payload marker, not an option.
This delta scheme is why URI paths become several small options. The path /sensors/temp is two Uri-Path options (number 11), one carrying sensors and one carrying temp. Each query parameter is a separate Uri-Query option (number 15). The media type of a payload is one Content-Format option (number 12) holding a compact numeric ID rather than a MIME string.
The parity of the option number decides how an unknown option is treated. Odd numbers are Critical: a server that does not understand a critical option in a request must reject it with 4.02 Bad Option. Even numbers are Elective: a recipient may silently ignore them. So Uri-Path (11, odd) is critical, while Content-Format (12, even) is elective.
4.02 Bad Option as "you sent a critical option I do not support," not as a payload error.0xFF where an option prefix is expected, options are done and the payload begins.Consider a Confirmable GET /temp carrying a 4-byte token. On the wire it is a short sequence of bytes, and every one has a defined meaning. The table walks the request; nothing here is padding.
Keep two counters while decoding: the byte offset in the UDP payload and the previous option number. The fixed header consumes offsets 0 through 3. TKL says the next four bytes are Token, so Options begin at offset 8. The first option byte is then decoded as a delta from previous option number 0. That is why 0xB4 means delta 11 and length 4: option number 11 is Uri-Path, and the next four bytes spell temp.
The server answers by piggybacking the response on the ACK. The reply begins 0x64 (Version 1, Type 2 = ACK, TKL 4), then Code 0x45 which decodes as 2.05 Content, then the same Message ID 0x3721 and the same 4-byte Token. A Content-Format option follows, then the 0xFF payload marker, then the reading itself (for example the ASCII bytes 32 32 2E 35 for "22.5").
The payload marker is not optional once payload bytes exist. Without 0xFF, a parser must keep reading option nibbles until the datagram ends; it cannot know that 32 starts a text reading. With the marker present, anything after it is application payload and is interpreted using Content-Format. In a trace review, mark the header, Token, each option, marker, and payload boundaries before arguing about application behavior.
Notice the two correlations at work. The ACK echoes the Message ID 0x3721 to confirm receipt at the messaging layer, and it echoes the Token to bind the answer to the request at the request/response layer. Both are visible directly in the bytes.
Before signing off a CoAP parser or trace review, verify that:
4.02 Bad Option, while unknown elective options are safe to ignore.0xFF payload marker is present when payload bytes exist and is never treated as an option prefix.After wire-format parsing is reliable, continue with CoAP Message Reliability and Exchange Contracts to see how those bytes drive retransmission, ACK matching, duplicate detection, and separate responses.