Skip to content

[Bug]: OpenCode timeout error formatting crashes and skips session recovery #12456

Description

@vedprakash2302

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Summary

When an OpenCode prompt submission and its cleanup abort both time out, openCodeRuntimeErrorDetail throws while formatting the timeout. This replaces the useful timeout error with a TypeError and prevents schedulePromptAdmissionRecovery from running. Repeated follow-up messages fail through the same path.

Steps to reproduce

The observed integration sequence was:

  1. Run a thread through the OpenCode provider in the Windows desktop app with a WSL server.
  2. The OpenCode event stream disconnects. T3 logs OpenCode connection lost. Reconnecting.
  3. Send another message while the OpenCode endpoint is unresponsive.
  4. session.promptAsync hits its 10-second timeout.
  5. The cleanup session.abort request hits its 1-second timeout.
  6. Formatting the cleanup timeout throws before T3 schedules prompt-admission recovery.

The trigger for the original OpenCode connection failure is not established. The error-formatting failure is independently reproducible with the current source:

import { openCodeRuntimeErrorDetail } from "./apps/server/src/provider/opencodeRuntime.ts";

const error = new Error();
Object.defineProperty(error, "message", { value: undefined });
openCodeRuntimeErrorDetail(error);
// TypeError: Cannot read properties of undefined (reading 'trim')

The installed T3 runtime contains an Effect TimeoutError constructor that calls super({ message }), while its timeout implementation calls new TimeoutError() without a message. That produces the error shape above. The worktree's newer Effect dependency supplies a timeout message, so triggering a normal timeout there alone does not reproduce the installed-runtime behavior.

Expected behavior

Report the original submission and cleanup timeouts without throwing from the diagnostic formatter. Execute the intended recovery path so a failed request does not leave subsequent messages failing against stale session state.

Actual behavior

Three follow-up messages at 12:27, 12:32, and 12:49 UTC on September 18 failed after approximately 11 seconds each with the same TypeError. No follow-up user message reached the persisted OpenCode conversation. The T3 thread eventually recorded a stopped session.

Impact

Blocks work completely in the affected thread.

Version or commit

T3 Code desktop 0.0.43-nightly.20260917.1866.

Installed WSL runtime artifact: sha256-92d4c19e9d405a67bd9e5dd39f2dcc4727577472b804acebc679556824c3ed70.

The unsafe formatter is also present in source at commit 19672fcf7b9aac6130133ab26f92c382d529399d and predates that branch's merge.

Environment

Windows desktop, WSL Linux server, OpenCode 1.18.31, provider/model github-copilot/gpt-6-astra.

Logs or stack traces

Relevant trace durations from one failed follow-up:

opencode.session.promptAsync  10002 ms  Interrupted
opencode.session.abort         1001 ms  Interrupted
sendTurn                      11017 ms  Failure

TypeError: Cannot read properties of undefined (reading 'trim')
    at openCodeRuntimeErrorDetail (.../t3:242573:46)
    at Array.<anonymous> (.../t3:245510:18)
    at sendTurn (.../t3:279695:40)
    at sendTurn (definition) (.../t3:245312:20)
    at sendTurn (.../t3:293056:32)
    at sendTurn (definition) (.../t3:279603:19)
    at processTurnStartRequested (.../t3:293229:89)
    at processTurnStartRequested (definition) (.../t3:292880:36)
    at processDomainEvent (.../t3:293258:46)
    at processDomainEvent (definition) (.../t3:293204:29)

Investigation

  • apps/server/src/provider/opencodeRuntime.ts assumes cause.message is a string whenever cause instanceof Error:

    if (cause instanceof Error && cause.message.trim().length > 0) return cause.message.trim();
  • apps/server/src/provider/Layers/OpenCodeAdapter.ts calls the formatter on Cause.squash(cleanupExit.cause) before calling schedulePromptAdmissionRecovery. The formatter's exception skips that recovery call.

  • A focused fix should handle missing or non-string error messages and cover the combined prompt-timeout/abort-timeout recovery path in a regression test.

Workaround

No verified workaround for the affected thread yet. The repository changes were committed locally and remained intact.

Activity

  1. juliusmarminge commented on Sep 18, 2026

    @juliusmarminge
    Member

    Triage

    Confirmed bug in current main (9ea9c3d5). This is not a duplicate, and it is not fixed by the open OpenCode recovery PRs.

    When OpenCode is unresponsive, sendTurn times out session.promptAsync (10s) and then the cleanup session.abort (1s). openCodeRuntimeErrorDetail is invoked on Cause.squash(cleanupExit.cause) before schedulePromptAdmissionRecovery. The formatter assumes every Error has a string message:

    if (cause instanceof Error && cause.message.trim().length > 0) return cause.message.trim();

    If message is missing or not a string, that throws TypeError: Cannot read properties of undefined (reading 'trim'). The useful timeout is replaced by a defect, recovery never runs, and later messages fail the same way (~11s). That matches the nightly 0.0.43-nightly.20260917.1866 traces.

    The reporter’s snippet still throws against current source. The installed-runtime trigger is Effect TimeoutError: the constructor does super({ message }), and Data.Error assigns that field onto the instance. new TimeoutError() (no argument) is an Error with message === undefined. Current tree Effect (4.0.0-rc.115) now passes Operation timed out after '…', so a live timeout here may not throw — the formatter is still unsafe, and nightly 1866 still used the no-message constructor.

    Related PRs do not fix this:

    Same throw site exists in failPromptAdmissionRecovery (cleanup abort formatting can skip emitUnexpectedExit). There are no tests for openCodeRuntimeErrorDetail.

    Suggested fix

    Guard cause.message as a string before .trim() (same pattern as legacySetupFailureDescription in apps/server/src/ws.ts). Keep the existing object / String(cause) fallbacks. Cover:

    1. openCodeRuntimeErrorDetail with undefined / non-string message (must return a string, never throw)
    2. prompt-timeout + abort-timeout still emits the cleanup warning and schedules prompt-admission recovery

    Do not wait on #11613 / #10805. Original OpenCode disconnect cause is unknown and separate from this formatter crash.

    No verified workaround for the stuck thread. A new thread or server restart may unblock that session only.

  2. added
    bugSomething is broken or behaving incorrectly.
    acceptedfeature request accepted
    via-triageFiled through npx t3 triage
    on Sep 18, 2026
  3. vedprakash2302 commented on Sep 18, 2026

    @vedprakash2302
    ContributorAuthor

    Screenshot showing the repeated errors after sending follow-up messages:

    Repeated OpenCode timeout error formatting failures

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

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions