Skip to content

fix: goose configure exits silently at the model picker#8790

Closed
ahmadelafify wants to merge 1 commit into
aaif-goose:mainfrom
ahmadelafify:fix/8373-configure-spinner-race
Closed

fix: goose configure exits silently at the model picker#8790
ahmadelafify wants to merge 1 commit into
aaif-goose:mainfrom
ahmadelafify:fix/8373-configure-spinner-race

Conversation

@ahmadelafify
Copy link
Copy Markdown

@ahmadelafify ahmadelafify commented Apr 24, 2026

Fixes #8373.

Summary

On macOS 26.4 (M5 Pro, tested in kitty and Terminal.app), goose configure exits with code 2 right after Model fetch complete prints. The model picker draws one frame and disappears before any keypress is registered.

The cause is a race between cliclack's spinner and the next prompt. spin.stop() flips a flag and returns, but the spinner's render thread keeps writing to the terminal for a few more ms. The next line opens the model picker, which puts stdin in raw mode and reads. Both widgets fight over the terminal and the picker's first read returns Err, which propagates out as exit 2.

Fix: drop the spinner explicitly and yield 50ms so cliclack tears the render thread down before the picker starts reading. The user does not see the delay.

     spin.stop(style("Model fetch complete").green());
+    // cliclack's spinner render thread outlives `stop()` and races the next
+    // prompt's raw-mode stdin read; drop and yield so the picker's
+    // `interact()` doesn't fail before any key is read. See #8373.
+    drop(spin);
+    tokio::time::sleep(std::time::Duration::from_millis(50)).await;

Testing

  • cargo build -p goose-cli --bin goose
  • goose configure → Claude Code → picker stays open, arrow keys and enter work.

Before:
https://github.com/user-attachments/assets/27d1d5b6-2d94-4f0b-9f0d-33d20fd7a52a

After:
https://github.com/user-attachments/assets/116f6d7c-84e8-4c6e-9845-81049615cc4b

@ahmadelafify ahmadelafify changed the title fix: goose configure exits silently at the model picker (#8373) fix: goose configure exits at model picker (#8373) Apr 24, 2026
cliclack's spinner spawns a render thread that outlives `stop()`. When
the next prompt opens stdin in raw mode immediately after `Model fetch
complete`, the still-alive spinner thread races the picker's first read
and `interact()?` propagates an error, exiting with code 2 before any
key is processed.

Drop the spinner explicitly and yield ~50ms before the model selector
opens so cliclack tears the render thread down first.

Fixes aaif-goose#8373.
@ahmadelafify ahmadelafify force-pushed the fix/8373-configure-spinner-race branch from b4bc964 to 7de9ad3 Compare April 24, 2026 04:19
@ahmadelafify ahmadelafify marked this pull request as ready for review April 24, 2026 06:27
@ahmadelafify ahmadelafify changed the title fix: goose configure exits at model picker (#8373) fix: goose configure dies at the model picker Apr 24, 2026
@ahmadelafify ahmadelafify changed the title fix: goose configure dies at the model picker fix: goose configure exits at the model picker Apr 24, 2026
@ahmadelafify ahmadelafify changed the title fix: goose configure exits at the model picker fix: goose configure exits silently at the model picker Apr 24, 2026
@jh-block jh-block self-assigned this May 5, 2026
@jh-block
Copy link
Copy Markdown
Collaborator

jh-block commented May 5, 2026

I don't think the diagnosis of the cause is quite right. In particular, "the spinner's render thread keeps writing to the terminal for a few more ms" cannot be true, because spin.stop() calls finish_with_state(), which calls finish_and_clear(), which joins the render thread. By the time spin.stop() returns, the render thread is no longer running.

The root cause is a bug in the console crate: it calls select() and then treats any interruption as a fatal error and returns Err. We issue SIGKILL to Claude Code and then proceed -- if the Claude Code subprocess exits after select() begins, SIGCHLD interrupts select() and triggers the bug. The sleep masks the problem because SIGCHLD arrives during the sleep, before select() is entered.

The real fix should be in the console crate, so I'll issue a PR there, but a robust workaround here is just to wait for the child process to be reaped before proceeding, instead of issuing the kill signal and immediately continuing without waiting. I'll open a PR here for that.

@jh-block
Copy link
Copy Markdown
Collaborator

jh-block commented May 5, 2026

Superseded by #9023

@jh-block jh-block closed this May 5, 2026
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.

"goose configure" quietly fails when trying to use Claude ACP

2 participants