Skip to content

Stopping during the workspace's initial scan ends the process with "Queue is closed" (exit 1) #323

Closed

Description

@antra-tess

What happens

If the framework is stopped while a workspace mount's initial scan is still running, the process ends with an unhandled error and exit code 1 instead of a clean stop:

17 |       throw new Error('Queue is closed');
                     ^
error: Queue is closed
      at push (agent-framework/src/queue.ts:17:17)
      at pushEvent (agent-framework/src/framework.ts:2711:16)
      at pushEvent (agent-framework/src/module-registry.ts:750:10)
      at initialScan (agent-framework/src/modules/workspace/index.ts:1010:17)

Seen on 0.22.0 (bfcfa9d) with connectome-host 0.10.0. It happened every time on hosts whose files mount takes more than a few seconds to scan: about 1,000 files and 1.5 GB in one case. In each case a host was started headless and told to shut down a few seconds after it reported ready, which is how provider-free rehearsals run.

Why

  • The scan isn't awaited. initialScan starts fire-and-forget: void this.initialScan(name), in modules/workspace/index.ts at lines 972 and 988.
  • The queue closes first. stop() closes the process queue, and pushEvent (framework.ts:2701) only tolerates a late tool-result after that (fix(lifecycle): late tool results and MCPL arrivals at stop() settle instead of rejecting unhandled #263). Every other event type still reaches queue.push, which throws.
  • A stop mid-scan throws twice. The scan's pass fails as the stop proceeds. Its catch then reports workspace:initial-scan-failed through this.ctx?.pushEvent(...) (line 1010), and that throws "Queue is closed" too.
  • Nothing catches it. The async function was started with void, so its rejection is unhandled and the runtime exits non-zero.

The workspace's own stop() drains mountTurns, but the queue it would report into is already closed by then.

Impact

  • A deliberate stop during the boot window reads as a crash: exit code 1 and an error stack in stderr.
  • Under Restart=on-failure (systemd) or launchd KeepAlive, a stop issued right after a start can become a restart.
  • The workspace event itself is harmless to lose. The exit code and the alarm are the problem.

Possible fixes

Either would do:

  • Drop late events in pushEvent. After the queue closes, drop (and log) every late event, not only tool-result, the way fix(lifecycle): late tool results and MCPL arrivals at stop() settle instead of rejecting unhandled #263 does for tool results.
  • Make the workspace module stop-aware. Keep the initialScan promise and await it (or abort it) in stop(), and skip pushEvent once this.stopped is set or the context is gone. The catch path also needs to stop throwing, since it runs exactly when a stop has interrupted the pass.

Related: #263 (late tool results after stop), #315 (start after stop).

🤖 Generated with Claude Code

Activity

  1. nissa-seru commented on Oct 14, 2026

    @nissa-seru
    Contributor

    #​316 fixes this, and it merged into main as da01e800 at 01:40Z on Oct 14. After stop() closes the queue, a module's event is now dropped with a log line naming the module, instead of reaching queue.push. The workspace's initial scan pushes through its module context (pushEvent in src/module-registry.ts), which now goes to pushModuleEvent in src/framework.ts. So the scan's events and its workspace:initial-scan-failed report are both dropped that way, and neither throws. 0.22.0 doesn't have it, so hosts get it in the next release. I'm closing this as fixed by #​316, and it can be reopened if a stop mid-scan still exits with an error on a build that has it.

    — Ada-1017

  2. added 2 commits that reference this issue on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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