paperclipai/paperclip · error
Codex turn response omitted turn.id
Error message
Codex turn response omitted turn.id
What it means
When the Codex turn.start RPC responds, the session reads response.turn.id and requires a non-empty id. An empty or missing id means the response shape is not what the Codex live transport contract promises, so the session rejects the pending turn, releases the admission, and throws.
Source
Thrown at packages/paperclip-runner/src/live/live-session.ts:1583
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;
try {
await this.#persist();
} catch (error) {
this.#rejectTurn(error);
this.#releaseTurnAdmission(admission);
await terminal.catch(() => undefined);View on GitHub (pinned to 01ad858492)
Solutions
- Check the Codex adapter/agent version matches what CapabilityLiveSession expects and upgrade/downgrade accordingly
- Log and inspect the raw turn.start response to confirm the turn.id field name and shape
- Fix test stubs/mocks to return a turn object with a non-empty id
- Add schema validation on the transport layer to fail fast with a clearer payload error
Example fix
// before (test stub)
{ turn: {} } // omitted turn.id -> throws
// after
{ turn: { id: 'turn_123', status: 'running' } } Defensive patterns
Strategy: validation
Validate before calling
const turn = (response as { turn?: { id?: unknown } }).turn;
if (typeof turn?.id !== 'string' || turn.id.length === 0) throw new Error('turn.start response missing turn.id'); Type guard
function hasTurnId(r: unknown): r is { turn: { id: string } } {
const t = (r as any)?.turn;
return !!t && typeof t.id === 'string' && t.id.length > 0;
} Try / catch
try {
await session.sendMessage(msg);
} catch (e) {
if ((e as Error).message === 'Codex turn response omitted turn.id') {
// inspect raw response; verify adapter/Codex versions before retry
} else throw e;
} Prevention
- Pin and verify Codex adapter/agent versions so the turn envelope shape matches
- Schema-validate turn.start responses at the transport boundary
- Keep test stubs faithful to the real response shape, including turn.id
When it happens
Trigger: Codex returns a turn object without an id field, or id is empty string; response deserialized into { turn: {} } due to a protocol/adapter version mismatch.
Common situations: Codex agent/adapter version drift where the turn envelope changed; mocked or stubbed Codex transport in tests returning incomplete turn payloads; corrupted/truncated RPC response.
Related errors
- Codex thread response omitted thread.id
- provider_initialize_protocol_error
- Codex turn response omitted turn.id
- Codex turn identity changed during start
- device-login promotion: the account identifier cannot form a
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/1a1e9ff7de65b471.
Report an issue: GitHub.