paperclipai/paperclip · error

Capability live turn start completed after admission teardow

Error message

Capability live turn start completed after admission teardown

What it means

After the Codex turn.start RPC resolves, sendMessage re-checks that its admission is still the session's current pending admission. If teardown released the admission while the start request was in flight, the turn result arrives too late to be bound, so the method cancels the terminal promise, releases resources, and throws.

Source

Thrown at packages/paperclip-runner/src/live/live-session.ts:1577

        runtimeWorkspaceRoots: [this.#config.workingDirectory],
        input: [userInput(value)],
      });
    } catch (error) {
      if (this.#pendingTurnAdmission !== admission) {
        await terminal.catch(() => undefined);
        throw error;
      }
      if (admission.cancellation !== null) {
        return this.#completeInterruptedAdmission(admission, userEntryId);
      }
      this.#rejectTurn(error);
      this.#releaseTurnAdmission(admission);
      await terminal.catch(() => undefined);
      throw error;
    }
    if (this.#pendingTurnAdmission !== admission) {
      await terminal.catch(() => undefined);
      throw new Error("Capability live turn start completed after admission teardown");
    }
    const turnId = text(record(response.turn).id);
    if (turnId.length === 0) {
      this.#rejectTurn(new Error("Codex turn response omitted turn.id"));
      this.#releaseTurnAdmission(admission);
      throw new Error("Codex turn response omitted turn.id");
    }
    if (this.#activeTurnId !== null && this.#activeTurnId !== turnId) {
      this.#rejectTurn(new Error("Codex turn identity changed during start"));
      this.#releaseTurnAdmission(admission);
      throw new Error("Codex turn identity changed during start");
    }
    if (this.#turnWaiter !== null) this.#activeTurnId = turnId;
    this.#bindAdmissionUser(userEntryId, turnId);
    const draftId = (this.#turnWaiter as TurnWaiter | null)?.draftId ?? null;
    const draft =
      draftId === null ? undefined : this.#transcript.find((entry) => entry.id === draftId);
    if (draft !== undefined && draft.turnId === null) draft.turnId = turnId;

View on GitHub (pinned to 01ad858492)

Solutions

  1. Avoid closing/failing the session while a turn.start request is outstanding
  2. Treat the thrown error as 'turn not started' and abandon the old session; retry on a fresh session
  3. Await sendMessage before invoking any teardown path; use lifecycle coordination (e.g. a busy flag)
  4. Investigate why turn.start was slow if this happens without explicit teardown

Example fix

// before
const p = session.sendMessage(msg);
session.fail(new Error('timeout')); // races turn.start
await p; // throws 'completed after admission teardown'
// after
await session.sendMessage(msg); // then decide about teardown
session.fail(new Error('timeout'));
Defensive patterns

Strategy: try-catch

Validate before calling

if (session.status === 'closed' || session.status === 'failed') throw new Error('session teardown in progress; abort send');

Type guard

null

Try / catch

try {
  await session.sendMessage(msg);
} catch (e) {
  if ((e as Error).message === 'Capability live turn start completed after admission teardown') {
    session = await createLiveSession(opts); // retry on a fresh session
  } else throw e;
}

Prevention

When it happens

Trigger: Session close/fail/interrupt completes between admission and the return of the turn.start RPC response; a slow turn.start response overlapping a teardown triggered elsewhere.

Common situations: Slow agent process responding to turn.start while a user or supervisor tears the session down; flaky transport causing long start latency and a concurrent timeout-triggered close.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/b24f58cd35331809. Report an issue: GitHub.