Skip to content

Codex ACP session/load failure surfaces as Internal Server Error and makes intact transcript inaccessible in UI #365

Closed

Description

@pedrotecinf

Summary

A stopped Codex session with a valid, readable transcript cannot be resumed after the ACP peer exits with peer disconnected before response. Every resume attempt fails during ACP session/load, and the CompozyOS desktop UI surfaces only Internal Server Error.

The daemon and HTTP API remain healthy. compozy session recap can read the complete persisted transcript, and compozy session repair --dry-run reports no transcript repair actions. The failure is specifically the runtime resume path plus the UI fallback behavior.

This appears related to #315, but the observable problem here is distinct:

Environment

  • CompozyOS CLI/runtime: 0.3.0-beta.13
  • CompozyOS desktop: 0.3.0-beta.13
  • Codex CLI: 0.147.0
  • Provider: codex
  • Model: gpt-5.6-sol
  • Reasoning effort: max
  • Speed: fast
  • macOS: 26.5.1 (25F80)
  • Architecture: Apple Silicon / Darwin

Reproduction

  1. Start CompozyOS and open a Codex-backed session.
  2. Let the session run a long tool-using turn.
  3. The Codex ACP peer exits before responding completely:
{"code":-32603,"message":"Internal error","data":{"error":"peer disconnected before response"}}
  1. The session transitions to:
state: stopped
health: dead
attachable: false
eligible_for_wake: false
stop_reason: error
failure.kind: process_exit
  1. Restart the daemon:
compozy daemon stop
compozy daemon start
  1. Reopen the session from the desktop UI or trigger a resume.
  2. The UI shows Internal Server Error. A new crash bundle is generated for each retry.

Repeated resume failure

The crash bundle records:

kind: load_session_failure
summary: ACP session/load failed: acp: load session failed:
load session "019ff5d2-966c-7281-827b-d09e53370493" for "general":
{"code":-32603,"message":"Internal error","data":{"error":"peer disconnected before response"}}

This reproduced at least three times after daemon restarts. Each attempt generated a load_session_failure crash bundle with the same underlying ACP error.

Evidence that the daemon and transcript are healthy

The daemon is alive and serves the UI/API normally:

GET http://localhost:2123/           -> 200 OK
GET http://localhost:2123/api/status -> 200 OK

Daemon status after restart:

Status: running
Network: ready
Active Sessions: 0

Session health:

{
  "state": "stopped",
  "health": "dead",
  "attachable": false,
  "eligible_for_wake": false,
  "ineligibility_reason": "session_health_dead"
}

Transcript repair dry run:

{
  "issues": [
    {
      "code": "terminal_event_already_exists",
      "severity": "info",
      "detail": "the final prompt turn already has a terminal event"
    }
  ],
  "actions": [],
  "persisted": false
}

compozy session recap SESSION_ID -o json successfully returned the persisted transcript, including the final error and subsequent failed resume attempts. This indicates the history is readable and does not require repair.

Runtime diagnostics also report the Codex ACP command as available:

provider: codex
command: npx -y @agentclientprotocol/codex-acp@latest
status: ok

Expected behavior

When an ACP session is dead/non-resumable but its transcript is intact, the UI should:

  1. Render the persisted transcript in read-only mode instead of returning Internal Server Error.
  2. Clearly explain that the provider runtime cannot be resumed.
  3. Offer an explicit Fork into new session or Continue from recap recovery action.
  4. Avoid repeatedly invoking session/load for a session already classified as health=dead, attachable=false, and eligible_for_wake=false.
  5. Preserve the original transcript and failure diagnostics.

Actual behavior

  • The UI tries to resume the dead session.
  • ACP session/load disconnects before response.
  • The UI surfaces only Internal Server Error.
  • Reopening/restarting repeats the same failure and creates another crash bundle.
  • The transcript is recoverable through CLI recap, but not usable from the normal UI flow.

Workaround

The following restored the UI while preserving history:

compozy session archive SESSION_ID
# restart only the desktop app; keep the daemon running

After archiving the dead session and restarting the desktop application:

Desktop app: running
Runtime attached: true
GET /api/status: 200

The session was archived, not removed, so its persisted history remains available through CLI recap/history.

Suggested fix

  • Before attempting ACP session/load, honor the daemon session health contract (dead, attachable=false, eligible_for_wake=false).
  • Separate transcript viewing from runtime attachment/resumption.
  • Map load_session_failure to a recoverable UI state instead of a generic HTTP 500.
  • Add a UI action that creates a new session seeded from deterministic recap/history.
  • Add a regression test covering: process exit -> stopped/dead session -> intact transcript -> UI read-only load without ACP resume.

Diagnostics

A redacted Compozy support bundle was generated locally with compozy support bundle --yes. It is not attached publicly because it contains broad workspace/session diagnostics, but it can be provided privately if needed.

Crash bundle schema: compozy.session_crash_bundle.v2
Failure kind: load_session_failure

Please let me know if maintainers want the redacted support bundle or specific sanitized log excerpts.

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

    Fields

    No fields configured for Bug.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions