paperclipai/paperclip · error

Codex turn response omitted turn.id

Error message

Codex turn response omitted turn.id

What it means

After sending the turn/start JSON-RPC request, startTurn reads response.turn.id; if it is missing or empty, no turn was actually accepted by the Codex app-server, so the method rolls back the optimistic turn-started state and throws this error. The rollback ensures semantic/terminal waiters released by the settled turn/start cannot observe an active turn for a request the provider never accepted.

Source

Thrown at packages/paperclip-runner/src/drivers/codex/codex-harness-session.ts:262

      throw error;
    } finally {
      this.turnStartPending = false;
      // Release a terminal notification that arrived and parked itself
      // while this turn/start was in flight. This runs before turn.accepted
      // below, in the same synchronous continuation, so a released waiter
      // never observes the terminal turn ahead of turn.accepted.
      releaseTurnStartSettled();
    }
    this.assertProtocolIntegrity();
    const turn = record(response.turn);
    const turnId = text(turn.id);
    if (turnId.length === 0) {
      // A start notification is only optimistic until the response validates.
      // Clear it before released semantic/terminal waiters can observe an
      // active turn for a request that was never accepted.
      this.activeTurnId = null;
      this.turnStarted = false;
      throw new Error("Codex turn response omitted turn.id");
    }
    if (this.activeTurnId !== null && this.activeTurnId !== turnId) {
      this.failProtocol(
        "turn_start_mismatch",
        "turn/start response disagreed with turn/started",
      );
      throw new Error("Codex turn identity changed during start");
    }
    this.activeTurnId ??= turnId;
    if (dispositionOnlyRecovery) {
      this.dispositionOnlyRecoveryTurnId = turnId;
    }
    this.emit("turn.accepted", { turnId }, { turnId });
    if (this.interruptQueued) {
      this.interruptQueued = false;
      await this.#sendInterrupt(turnId, "queued_before_start");
    }
    return {

View on GitHub (pinned to 01ad858492)

Solutions

  1. Check the Codex app-server version and pin one whose turn/start response includes turn.id; update paperclip-runner if a schema change requires a fix.
  2. Log the raw turn/start response to confirm the shape; if a proxy/middleware is in the path, verify it is not dropping the turn field.
  3. Retry startTurn after verifying session state was rolled back (activeTurnId is null); if it persists, recreate the session.

Example fix

// before (naive caller)
const { turnId } = await session.startTurn({ message });
// after
try {
  const { turnId } = await session.startTurn({ message });
} catch (e) {
  if (e.message === "Codex turn response omitted turn.id") {
    await recreateSessionAndResubmit();
  } else throw e;
}
Defensive patterns

Strategy: try-catch

Type guard

function turnResponseHasId(response: unknown): response is { turn: { id: string } } {
  const r = response as { turn?: { id?: unknown } };
  return typeof r?.turn?.id === "string" && r.turn.id.length > 0;
}

Try / catch

try {
  const { turnId } = await session.startTurn({ message });
} catch (e) {
  if (e.message === "Codex turn response omitted turn.id") {
    // optimistic state was rolled back by the library; safe to resubmit
    // after verifying the app-server version / response shape
    await resubmitTurnAfterShapeCheck();
  } else throw e;
}

Prevention

When it happens

Trigger: The turn/start RPC resolves successfully but its response payload has no turn object or turn.id is an empty/non-string value — e.g. an app-server version returning a different response shape, a proxy stripping fields, or the provider rejecting the turn without a JSON-RPC error.

Common situations: Upgrading or downgrading the Codex app-server so turn/start's response schema changed; running against a mock or misconfigured transport; provider-side rejection surfaced as a success-shaped empty response instead of a protocol error.

Related errors


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