Skip to content

Stop response-handler errors from poisoning the nREPL response queue#3896

Merged
bbatsov merged 1 commit intomasterfrom
demote-dispatch-errors
Apr 29, 2026
Merged

Stop response-handler errors from poisoning the nREPL response queue#3896
bbatsov merged 1 commit intomasterfrom
demote-dispatch-errors

Conversation

@bbatsov
Copy link
Copy Markdown
Member

@bbatsov bbatsov commented Apr 29, 2026

Found during a wider audit of request handling.

nrepl-client-filter decodes a batch of responses from the wire and walks them in a while loop, dispatching each in turn. A with-demoted-errors guard wrapped the global nrepl-response-handler-functions hook but stopped there -- the per-request nrepl--dispatch-response call ran unprotected.

If that call signaled (because a callback threw, or because no handler was registered for the response's id), the while (queue-head response-q) loop aborted and any later decoded responses sitting in the queue were dropped on the floor. The next response stream might keep working, but anything already decoded was lost.

This PR makes two changes:

  1. Wrap nrepl--dispatch-response in with-demoted-errors too. Handler bugs become log entries, not stream corruption.
  2. Soften nrepl--dispatch-response's no-callback case from error to message. The dispatcher cannot do anything actionable with an unknown id; logging is sufficient and avoids forcing the filter to demote.

Two new specs in test/nrepl-client-tests.el cover the soft no-handler path and lock in the dispatcher's contract (errors propagate unless the filter wraps you).

`nrepl-client-filter' decodes a batch of responses from the wire and
walks them in a `while' loop, dispatching each in turn.  A demoted-
errors wrapper guarded the global `nrepl-response-handler-functions'
hook but stopped there -- the per-request `nrepl--dispatch-response'
call ran unprotected.  If that call signaled (because of a buggy
callback, or because no handler was registered for the response's id),
the loop aborted and any later decoded responses sitting in the queue
were dropped.

Two changes:

- Wrap `nrepl--dispatch-response' in `with-demoted-errors' too.
  Handler bugs are logged but no longer corrupt the response stream.

- Soften `nrepl--dispatch-response''s no-callback case from `error'
  to `message'.  The dispatcher cannot do anything actionable with an
  unknown id; logging is sufficient.

Adds two specs in test/nrepl-client-tests.el covering the soft
no-handler path and locking in the dispatcher's "errors propagate
unless the filter wraps you" contract.
@bbatsov bbatsov force-pushed the demote-dispatch-errors branch from 3190a37 to 3f21e81 Compare April 29, 2026 19:00
@bbatsov bbatsov merged commit b95dcc9 into master Apr 29, 2026
13 checks passed
@bbatsov bbatsov deleted the demote-dispatch-errors branch April 29, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant