Skip to content

Keep completion alive when RDoc document retrieval fails#1229

Merged
tompng merged 1 commit into
ruby:masterfrom
pocke:keep-completion-alive-on-rdoc-error
Jul 16, 2026
Merged

Keep completion alive when RDoc document retrieval fails#1229
tompng merged 1 commit into
ruby:masterfrom
pocke:keep-completion-alive-on-rdoc-error

Conversation

@pocke

@pocke pocke commented Jul 15, 2026

Copy link
Copy Markdown
Member

Summary

The autocompletion documentation dialog could crash the whole IRB session when loading RDoc documentation failed. This makes RDoc document retrieval failable: the error is shown in the dialog and completion (and the session) keeps working.

Steps to reproduce

With Ruby::Box enabled, IRB crashes during completion (see the details below). The steps below reproduce it that way, but the crash can happen in any case where loading RDoc documentation fails, not only under Ruby::Box.

  1. Use a Ruby build that provides Ruby::Box (e.g. a ruby-dev build) and start IRB with the box enabled:

    RUBY_BOX=1 irb
    
  2. Type 1. and press to trigger method-name completion.

Any receiver reproduces it; the trigger is rendering the documentation dialog for a completion candidate, which loads RDoc data from disk.

Expected behavior

The completion candidates and their documentation dialog are shown, and IRB keeps running even when the documentation cannot be loaded.

Actual behavior

IRB terminates with an uncaught exception:

.../rdoc/store.rb:1190:in 'Marshal.load': undefined class/module RDoc:: (ArgumentError)
	from .../rdoc/store.rb:1190:in 'block in RDoc::Store#marshal_load'
	from .../rdoc/store.rb:835:in 'RDoc::Store#load_method'
	...
	from .../irb/input-method.rb:in 'IRB::RelineInputMethod#rdoc_dialog_contents'
	from .../reline/line_editor.rb:in 'Reline::LineEditor::Dialog#call'
	...

Screen records

before:

2026-07-15.224319.mp4

after:

2026-07-15.224351.mp4

Environment

irb(main):001> irb_info
Ruby version: 4.0.6
IRB version: irb 1.18.0 (2026-04-21)
InputMethod: RelineInputMethod with Reline 0.6.3
Completion: Autocomplete, ReplTypeCompletor: 0.1.12, Prism: 1.8.1, RBS: 3.10.0
.irbrc paths: /home/pocke/.irbrc
RUBY_PLATFORM: x86_64-linux
LANG env: C.UTF-8
East Asian Ambiguous Width: 1

Root cause

The dialog loads RDoc .ri data via Marshal.load, and rdoc_dialog_contents only rescued RDoc::RI::Driver::NotFoundError. Any other error raised during retrieval propagated through Reline's dialog proc and terminated the REPL.

Here it is triggered by a Ruby core bug: under Ruby::Box (RUBY_BOX=1), Marshal.load fails to resolve class references and raises ArgumentError: undefined class/module ... (https://bugs.ruby-lang.org/issues/22090). That bug lives in Ruby itself and cannot be fixed here, but RDoc document retrieval is a fragile external dependency that IRB should treat as failable regardless of the specific cause.

Fix

Treat only the fragile part -- fetching the document from the RDoc driver -- as failable, and leave rendering untouched.

  • Extract the RDoc driver calls into retrieve_rdoc_document, and rescue around that call alone in rdoc_dialog_contents. NotFoundError still means "no document" and stays silent; any other StandardError is turned into an error document by rdoc_error_document.
  • RDoc::Markup::ToAnsi rendering and the dialog layout stay outside the rescue on purpose: a failure there is IRB/Reline's own bug and should surface rather than be swallowed.
  • The error document shows the exception class and message where the document would appear, so the user learns why documentation is unavailable while completion keeps working. The "Press Alt+d to read the full document" hint is omitted on error, since there is no full document to open.
  • The narrow dialog does not show the backtrace. To investigate such a failure, run IRB with -d (which sets $DEBUG): the error is then re-raised with its full backtrace instead of being swallowed. The dialog points to this with a "Restart IRB with -d to see the backtrace." hint.

Out of scope

The Alt+D full-document path (display_document) is left unchanged. In the error state there is no document to open, so pressing Alt+D behaves as before.

## Summary

The autocompletion documentation dialog could crash the whole IRB session when loading RDoc documentation failed. This makes RDoc document retrieval failable: the error is shown in the dialog and completion (and the session) keeps working.

## Steps to reproduce

With `Ruby::Box` enabled, IRB crashes during completion (see the details below). The steps below reproduce it that way, but the crash can happen in any case where loading RDoc documentation fails, not only under `Ruby::Box`.

1. Use a Ruby build that provides `Ruby::Box` (e.g. a ruby-dev build) and start IRB with the box enabled:

   ```
   RUBY_BOX=1 irb
   ```

2. Type `1.` and press <Tab> to trigger method-name completion.

Any receiver reproduces it; the trigger is rendering the documentation dialog for a completion candidate, which loads RDoc data from disk.

## Expected behavior

The completion candidates and their documentation dialog are shown, and IRB keeps running even when the documentation cannot be loaded.

## Actual behavior

IRB terminates with an uncaught exception:

```
.../rdoc/store.rb:1190:in 'Marshal.load': undefined class/module RDoc:: (ArgumentError)
	from .../rdoc/store.rb:1190:in 'block in RDoc::Store#marshal_load'
	from .../rdoc/store.rb:835:in 'RDoc::Store#load_method'
	...
	from .../irb/input-method.rb:in 'IRB::RelineInputMethod#rdoc_dialog_contents'
	from .../reline/line_editor.rb:in 'Reline::LineEditor::Dialog#call'
	...
```

## Environment

```
irb(main):001> irb_info
Ruby version: 4.0.6
IRB version: irb 1.18.0 (2026-04-21)
InputMethod: RelineInputMethod with Reline 0.6.3
Completion: Autocomplete, ReplTypeCompletor: 0.1.12, Prism: 1.8.1, RBS: 3.10.0
.irbrc paths: /home/pocke/.irbrc
RUBY_PLATFORM: x86_64-linux
LANG env: C.UTF-8
East Asian Ambiguous Width: 1
```

## Root cause

The dialog loads RDoc `.ri` data via `Marshal.load`, and `rdoc_dialog_contents` only rescued `RDoc::RI::Driver::NotFoundError`. Any other error raised during retrieval propagated through Reline's dialog proc and terminated the REPL.

Here it is triggered by a Ruby core bug: under `Ruby::Box` (`RUBY_BOX=1`), `Marshal.load` fails to resolve class references and raises `ArgumentError: undefined class/module ...` (https://bugs.ruby-lang.org/issues/22090). That bug lives in Ruby itself and cannot be fixed here, but RDoc document retrieval is a fragile external dependency that IRB should treat as failable regardless of the specific cause.

## Fix

Treat only the fragile part -- fetching the document from the RDoc driver -- as failable, and leave rendering untouched.

- Extract the RDoc driver calls into `retrieve_rdoc_document`, and rescue around that call alone in `rdoc_dialog_contents`. `NotFoundError` still means "no document" and stays silent; any other `StandardError` is turned into an error document by `rdoc_error_document`.
- `RDoc::Markup::ToAnsi` rendering and the dialog layout stay outside the rescue on purpose: a failure there is IRB/Reline's own bug and should surface rather than be swallowed.
- The error document shows the exception class and message where the document would appear, so the user learns why documentation is unavailable while completion keeps working. The "Press Alt+d to read the full document" hint is omitted on error, since there is no full document to open.
- The narrow dialog does not show the backtrace. To investigate such a failure, run IRB with `-d` (which sets `$DEBUG`): the error is then re-raised with its full backtrace instead of being swallowed. The dialog points to this with a "Restart IRB with -d to see the backtrace." hint.

## Out of scope

The Alt+D full-document path (`display_document`) is left unchanged. In the error state there is no document to open, so pressing Alt+D behaves as before.
@pocke
pocke force-pushed the keep-completion-alive-on-rdoc-error branch from 28c6734 to d900ff8 Compare July 15, 2026 13:22
@pocke
pocke marked this pull request as ready for review July 15, 2026 13:46

@tompng tompng left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.
This will also fixes RDoc's Marshal load related problem such as http://github.com/ruby/rdoc/pull/1549
Thank you 👍

@tompng
tompng merged commit fba3999 into ruby:master Jul 16, 2026
33 of 40 checks passed
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.

2 participants