ESP8266 UART Reception Has Two Queues, and Only One Contains the Bytes
An ESP8266 serial receiver can have unread data even after it stops receiving UART_DATA notifications. The RTOS SDK driver moves payload bytes into a receive ring and separately posts event descriptors to a FreeRTOS queue. Their capacities and failure paths are different. Increasing one does not establish that the other cannot overflow.
This source review fixes ESP8266 RTOS SDK v3.4 to commit 89a3f254b63819035f65d9c5dcdae8864f1a6a8a and focuses on UART0 reception. It is a legacy-maintenance analysis, not a current-support claim; assess Espressif's maintenance advisory separately. No serial traffic or board timing was measured.
Draw both paths from the interrupt handler
The UART API distinguishes the receive ring's byte capacity from the event queue's depth. uart_event_t carries an event type and a size for UART_DATA; payload bytes are obtained through uart_read_bytes. The installation API also permits omitting the event queue entirely.
In the pinned driver, the interrupt handler first attempts the receive-ring transfer. Later, it attempts xQueueSendFromISR for the event. If the event queue is full, that send can fail without undoing a successful payload transfer. Consequently, event delivery and byte availability are not interchangeable evidence.

Original dual-path diagram. It represents source behavior, not a measured overflow trace.
Do not make notification loss an indefinite sleep
Consider a receiver that waits forever for one event, reads exactly that event's size, then waits again. Under event congestion, some bytes can remain in the receive ring without a corresponding retained notification. If the sender then becomes quiet, the application should not rely on a future character to wake it and rescue old data.
A proposed design gives one task ownership of reads, parser state and recovery. Events prompt that owner to inspect the receive path, while a bounded wait permits reconciliation when notifications are absent. The exact wait and drain budget must meet the protocol's latency requirements. A timeout is a fallback opportunity, not proof that no bytes were lost.
Once the owner drains more than a single event describes, old event sizes can become stale as byte-accounting instructions. Treat them as event information rather than a ledger authorizing repeated blocking reads. Bound each read by the destination buffer and use its actual return value. Do not let a stale size make the task wait indefinitely for replacement bytes.
Distinguish ring pressure from hardware loss
The driver has a stash for a FIFO chunk that cannot immediately enter the receive ring. On that failure it marks the buffer-full state and disables the relevant receive interrupts. Its read path can later move the stash into available ring space and re-enable reception. UART_BUFFER_FULL therefore deserves a different diagnosis from simply asserting that the entire current frame has already disappeared.
A UART_FIFO_OVF path instead resets the hardware FIFO and reports overflow. Continuing to parse the remaining stream as if it were contiguous is unsafe. The protocol owner needs an explicit discontinuity policy, such as abandoning an incomplete frame and seeking a validated next boundary.
These source observations are reasons to qualify the actual recovery path, not a guarantee of lossless operation under ring pressure. Incoming characters may continue while the application catches up. Whether hardware flow control and the peer can stop them in time requires separate electrical and timing evidence.
Understand the example's deliberate discard policy
Espressif's UART event example handles both buffer-full and FIFO-overflow events by flushing input and resetting the event queue. Its comments identify this as example behavior. That is a discard-and-resume policy, not a promise to preserve all received commands.
If adapting that policy, also invalidate any partially assembled application frame and make the loss observable. Flushing a driver buffer cannot clear bytes already retained by a parser. Coordinate the transition through the receive owner so another task does not simultaneously consume the stream or reset its state.
Also distinguish input flushing from transmit completion. The driver header describes uart_flush as an input operation; uart_wait_tx_done addresses transmission completion. A convenient function name is insufficient justification for substituting one in a recovery sequence.
Preserve error evidence outside a saturated queue
An error event can encounter the same full event queue as a data notification. Periodically draining bytes solves a progress problem, but does not recover an error report that was never admitted. A protocol checksum or sequence number may detect some discontinuities; neither proves that every loss will be detected under every traffic pattern.
Where complete error accounting is required, review a driver-level counter or another supported persistent diagnostic path, with appropriate interrupt synchronization. Do not claim such accounting already exists merely because the example logs error events. Any instrumentation patch becomes part of the versioned implementation and requires its own review.
Exercise event pressure independently of byte pressure
Proposed qualification first creates frequent small bursts while delaying event consumption, then separately drives the receive ring toward capacity. Observe payload bytes admitted and consumed, event-send failures, hardware overflows, parser resets and accepted records. Use a controlled sender with recognizable framing and a permitted way to pause it.
Include a final quiet interval after congestion. It tests whether old bytes remain stranded when no new interrupt arrives. Also inject a gap inside a frame and check that recovery does not combine its prefix with a later message. These are acceptance procedures, not reported test results.
A robust receiver has a byte-stream owner, bounded notification handling and a defined response to discontinuity. The event queue helps that owner run; it is not the received data itself or an infallible error log.