Skip to content

repl: catch all errors during tab completion#15255

Merged
xokdvium merged 1 commit into
NixOS:masterfrom
obsidiansystems:fix-repl-tab-crash
Feb 16, 2026
Merged

repl: catch all errors during tab completion#15255
xokdvium merged 1 commit into
NixOS:masterfrom
obsidiansystems:fix-repl-tab-crash

Conversation

@amaanq
Copy link
Copy Markdown
Member

@amaanq amaanq commented Feb 16, 2026

Motivation

The tab completion handler in completePrefix only caught ParseError,
EvalError, BadURL, and FileNotFound. Other error types like
JSONParseError (which derives from Error, not EvalError) escaped
the catch block and propagated through editline's C code as undefined
behavior, crashing the REPL. This happened when tab-completing
expressions like (builtins.fromJSON "invalid"). where evaluation
throws a non-EvalError exception.

This commit marks completionCallback and listPossibleCallback as
noexcept with function-try-blocks that catch all exceptions at the
C/C++ boundary, preventing any exception from reaching editline.

Context


Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

@amaanq amaanq requested a review from edolstra as a code owner February 16, 2026 20:31
@github-actions github-actions Bot added the repl The Read Eval Print Loop, "nix repl" command and debugger label Feb 16, 2026
@amaanq amaanq force-pushed the fix-repl-tab-crash branch 3 times, most recently from 5ab8b84 to 9c76207 Compare February 16, 2026 20:55
Comment thread src/libcmd/repl-interacter.cc
The tab completion handler in `completePrefix` only caught `ParseError`,
`EvalError`, `BadURL`, and `FileNotFound`. Other error types like
`JSONParseError` (which derives from `Error`, not `EvalError`) escaped
the catch block and propagated through editline's C code as undefined
behavior, crashing the REPL. This happened when tab-completing
expressions like `(builtins.fromJSON "invalid").` where evaluation
throws a non-`EvalError` exception.

This commit marks `completionCallback` and `listPossibleCallback` as
`noexcept` with function-try-blocks that catch all exceptions at the
C/C++ boundary, preventing any exception from reaching editline.

Fixes NixOS#15133.
@amaanq amaanq force-pushed the fix-repl-tab-crash branch from 9c76207 to be6e72f Compare February 16, 2026 21:10
@xokdvium xokdvium enabled auto-merge February 16, 2026 21:13
@xokdvium xokdvium added this pull request to the merge queue Feb 16, 2026
Merged via the queue into NixOS:master with commit e7e5eaa Feb 16, 2026
15 checks passed
amaanq added a commit to obsidiansystems/nix that referenced this pull request Feb 23, 2026
This commit verifies that `writeFull` with `allowInterrupts=false` completes
successfully when the interrupt flag is set. This prevents regressions
like the one fixed by NixOS#15255 where `write()` called `checkInterrupt()`
unconditionally.
amaanq added a commit to obsidiansystems/nix that referenced this pull request Feb 23, 2026
This commit verifies that `writeFull` with `allowInterrupts=false` completes
successfully when the interrupt flag is set. This prevents regressions
like the one fixed by NixOS#15255 where `write()` called `checkInterrupt()`
unconditionally.
@amaanq amaanq deleted the fix-repl-tab-crash branch March 25, 2026 05:13
brittonr pushed a commit to brittonr/nix that referenced this pull request Apr 1, 2026
repl: catch all errors during tab completion
brittonr pushed a commit to brittonr/nix that referenced this pull request Apr 1, 2026
This commit verifies that `writeFull` with `allowInterrupts=false` completes
successfully when the interrupt flag is set. This prevents regressions
like the one fixed by NixOS#15255 where `write()` called `checkInterrupt()`
unconditionally.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

repl The Read Eval Print Loop, "nix repl" command and debugger

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nix repl: fromJSON => Error => tabcomplete => crash

2 participants