Skip to content

Comments

🥅 Only print parser debug for unhandled errors#600

Merged
nevans merged 1 commit intomasterfrom
response_parse_error-debug-only-unhandled
Feb 9, 2026
Merged

🥅 Only print parser debug for unhandled errors#600
nevans merged 1 commit intomasterfrom
response_parse_error-debug-only-unhandled

Conversation

@nevans
Copy link
Collaborator

@nevans nevans commented Feb 9, 2026

Previously, ResponseParser#parse_error would immediately print its debug information, prior to raising. This commit changes #parse_error to simply raise the exception. The parse error debug detailed_message will be printed by #parse (which is currently the only entrypoint into the parser).

Motivation

For years, I've used custom ResponseParser subclasses which rescue specific parse errors and can attempt to parse using a fallback approach (usually backtracking first). And I'd like to merge some some of this code back into in the core ResponseParser. That means that parse_error can be recoverable inside the parser.

Without this change, parse error recovery would either print spurious parse errors, or require temporarily disabling debug. Both approaches add significant difficulty to debugging.

Unfortunately, throw/catch cannot easily be used for this purpose, because the parse error's #backtrace and #cause are essential for debugging parse errors, especially when working with backtracking.

@nevans nevans changed the title 🥅 Only print parser debug for _unhandled_ errors 🥅 Only print parser debug for unhandled errors Feb 9, 2026
Previously, `ResponseParser#parse_error` would _immediately_ print its
debug information, prior to raising.  This commit changes `#parse_error`
to simply _raise_ the exception.  The parse error debug detailed_message
will be printed by `#parse` (which is currently the only entrypoint into
the parser).

Motivation: For years, I've used custom ResponseParser subclasses which
rescue specific parse errors and can attempt to parse using a fallback
approach (usually backtracking first).  And I'd like to merge some some
of this code back into in the core ResponseParser.  That means that
`parse_error` can be recoverable inside the parser.

Without this change, parse error recovery would either print spurious
parse errors, or require temporarily disabling debug.  Both approaches
add significant difficulty to debugging.

Unfortunately, `throw`/`catch` cannot be used for this purpose, because
the parse error's `#backtrace` and `#cause` are essential for debugging
parse errors, _especially_ when working with backtracking.
@nevans nevans force-pushed the response_parse_error-debug-only-unhandled branch from f43eb86 to feefc51 Compare February 9, 2026 21:14
Base automatically changed from response_parse_error-detailed_message to master February 9, 2026 21:15
@nevans nevans marked this pull request as ready for review February 9, 2026 21:16
@nevans nevans merged commit 5f74b9d into master Feb 9, 2026
39 checks passed
@nevans nevans deleted the response_parse_error-debug-only-unhandled branch February 9, 2026 21:17
nevans added a commit that referenced this pull request Feb 10, 2026
`resp-text` is defined as:
```abnf
resp-text = ["[" resp-text-code "]" SP] text     ; RFC3501
resp-text = ["[" resp-text-code "]" SP] [text]   ; RFC9051
```
And our even more lenient interpretation (which incorporates RFC9051
errata), is this:
```abnf
resp-text = ["[" resp-text-code "]" [SP [text]] / [text]
```

And, although the `resp-text-code` grammar is elaborate, the final
alternative is a superset of every other alternative (in both RFCs):
```abnf
resp-text-code /= atom [SP 1*<any TEXT-CHAR except "]">]
```

Notice that `text` is a superset of `atom`, `SP`, `"["`, `"]"`, and
every other allowed character in `resp-text-code`.  So, even if
`resp-text-code` fails, `resp-text` may still succeed by parsing
everything as `text`.

However, (prior to this commit) the parser commits to `resp-text-code`
as soon as `"["` is encountered at the beginning of `resp-text`.  If
what follows is not `resp-text-code`, maybe it doesn't begin with an
`atom` or it doesn't have a closing `"]"`, then we fail to parse
`resp-text` correctly.

Fixing this requires either looking further ahead more than a single
token or backtracking when `resp-text-code` fails to parse.  In this
case, I think backtracking is the best approach.  We don't need to worry
about backtracking taking exponential time, because the fallback
(`text`) is exceptionally simple (does not call any other productions),
will parse all the way up to the next CRLF, and so nothing backtrackable
can be nested.

This uses `ResponseParser#current_state` that was added for #599 and
relies on #600 to ensure that debug error messages are not printed when
backtracking.

Fixes #597.
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