Skip to content

Auto-review session stuck on "Waiting for terminal" when Ghostty createSurface() fails #217

@dhilgaertner

Description

@dhilgaertner

Summary

Auto-review created a review session overnight but the terminal never appeared — the session hung indefinitely on the "Waiting for terminal" screen. The underlying cause appears to be a failed Ghostty surface creation, after which TerminalManager happily returns the existing (broken) view on subsequent lookups instead of failing the session or retrying.

Repro

  1. Run latest crow on a Mac mini, leave it overnight with auto-review enabled and a watched repo that receives a "request changes" / review-requested event.
  2. Auto-review fires (in this case for radiusmethod/tanzanite#155).
  3. In the morning the session exists in the sidebar but the terminal pane is stuck on "Waiting for terminal".

Logs (2026-04-29, ~08:24 local)

[SessionService] Cloning radiusmethod/tanzanite into /Users/dustinhilgaertner/Projects/crow-reviews/tanzanite-pr-155
[TerminalManager] trackReadiness for 06CF4874-E79D-4D01-B76C-700995FB6518
[TerminalManager] preInitialize(06CF4874-...) — creating surface in offscreen window
[GhosttyApp] Unhandled action: tag=ghostty_action_tag_e(rawValue: 41)
[Ghostty] createSurface() FAILED — surface is nil
[SessionService] Created review session 'review-tanzanite-155' for https://github.com/radiusmethod/tanzanite/pull/155
[TerminalManager] surface(for: 06CF4874-...) — returning EXISTING view
[GhosttyApp] Unhandled action: tag=ghostty_action_tag_e(rawValue: 41)
[Ghostty] createSurface() FAILED — surface is nil

After that point the only repeating log entries are [IssueTracker] refresh: lines — there are no further terminal-related events, which means there's no retry, no surfacing of the failure, and no path out of the stuck state without restarting the app.

Observations / hypotheses

  • Ghostty.createSurface() returned nil, but the terminal id 06CF4874-... was still registered with TerminalManager. The next surface(for:) call returned the existing broken entry rather than treating nil-surface as "needs reinit".
  • The unhandled ghostty_action_tag_e(rawValue: 41) from GhosttyApp happens immediately before each surface failure — could be related; worth confirming what action 41 corresponds to in the current Ghostty SDK build.
  • The session was created (Created review session 'review-tanzanite-155') after the first surface failure, so session creation doesn't gate on terminal readiness. That's fine in general, but combined with the lack of retry, it means the user-visible state is "session exists, terminal forever pending".

Expected behavior

At minimum one of:

  1. createSurface() failure triggers a bounded retry on the same terminal id, with backoff.
  2. After N failures the session surfaces an error state in the UI ("Terminal failed to launch — retry / open logs") instead of "Waiting for terminal" forever.
  3. TerminalManager.surface(for:) should not return an entry whose surface is nil — treat that as a miss and re-preInitialize.

Auto-review specifically should also probably mark the session as failed (or auto-retry the whole review) if the terminal can't come up within some deadline, so overnight runs don't silently no-op.

Environment

  • Latest crow (running overnight on a Mac mini)
  • Auto-review enabled
  • Triggering event: review requested on radiusmethod/tanzanite#155

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions