Yeachan-Heo/oh-my-codex · error · Error

bound session retained close failed

Error message

bound session retained close failed: ${closeEvidence.error?.message ?? "unknown error"}

What it means

During post-launch handling, closing the retained launch session binding (closeLaunchSessionBindingOnce) returned status 'failed', and the error message is surfaced (or 'unknown error' if absent).

Solutions

  1. Read the embedded error message to identify the underlying cause (usually a file or state issue)
  2. Remove/repair the stale binding artifact for that session and re-run the close/cleanup command
  3. Avoid running multiple cleanup commands against the same session simultaneously
Defensive patterns

Strategy: try-catch

Try / catch

try { await finalize(); } catch (e) {
  if ((e as Error).message.startsWith('bound session retained close failed')) { /* read embedded cause, clear stale binding, retry once */ }
}

Prevention

When it happens

Trigger: closeLaunchSessionBindingOnce fails on I/O (binding file removed/locked) or on a state comparison mismatch while finalizing the retained binding.

Common situations: Concurrent CLI invocations finalizing the same binding, or a partially corrupted binding file after a crash mid-write.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/938b655f7571fcb2. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/index.ts:7391

      context: buildNativeHookBaseContext(cwd, sessionId, normalizedEvent, {
        project_path: cwd,
        project_name: basename(cwd),
        duration_ms: durationMs,
        reason: "session_exit",
        status: normalizedEvent === "failed" ? "failed" : "finished",
        ...(process.exitCode !== undefined
          ? { exit_code: process.exitCode }
          : {}),
        ...(errorSummary ? { error_summary: errorSummary } : {}),
      }),
    });
  } catch (err) {
    logCliOperationFailure(err);
    // Non-fatal
  }
  const closeEvidence = await closeLaunchSessionBindingOnce(binding);
  if (closeEvidence.status === "failed") {
    throw new Error(`bound session retained close failed: ${closeEvidence.error?.message ?? "unknown error"}`);
  }
}

export async function runDetachedSessionPostLaunch(
  cwd: string,
  sessionId: string,
  projectLocalCodexHomeForCleanup?: string,
  runtimeCodexHomeForCleanup?: string,
  releaseMarkerPath?: string,
): Promise<void> {
  // The detached child is intentionally unbound: it must never perform parent
  // pointer finalization or cleanup after the release barrier. It still owns
  // every non-pointer terminal lifecycle responsibility.
  const failures: unknown[] = [];
  const strict = async (operation: () => Promise<unknown>): Promise<void> => {
    try { await operation(); } catch (error) { failures.push(error); }
  };

View on GitHub (pinned to 3ad79a8a6f)