{"record":{"id":"1a1e9ff7de65b471","repo":"paperclipai/paperclip","slug":"codex-turn-response-omitted-turn-id-1a1e9f","errorCode":null,"errorMessage":"Codex turn response omitted turn.id","messagePattern":"Codex turn response omitted turn\\.id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/live/live-session.ts","lineNumber":1583,"sourceCode":"        throw error;\n      }\n      if (admission.cancellation !== null) {\n        return this.#completeInterruptedAdmission(admission, userEntryId);\n      }\n      this.#rejectTurn(error);\n      this.#releaseTurnAdmission(admission);\n      await terminal.catch(() => undefined);\n      throw error;\n    }\n    if (this.#pendingTurnAdmission !== admission) {\n      await terminal.catch(() => undefined);\n      throw new Error(\"Capability live turn start completed after admission teardown\");\n    }\n    const turnId = text(record(response.turn).id);\n    if (turnId.length === 0) {\n      this.#rejectTurn(new Error(\"Codex turn response omitted turn.id\"));\n      this.#releaseTurnAdmission(admission);\n      throw new Error(\"Codex turn response omitted turn.id\");\n    }\n    if (this.#activeTurnId !== null && this.#activeTurnId !== turnId) {\n      this.#rejectTurn(new Error(\"Codex turn identity changed during start\"));\n      this.#releaseTurnAdmission(admission);\n      throw new Error(\"Codex turn identity changed during start\");\n    }\n    if (this.#turnWaiter !== null) this.#activeTurnId = turnId;\n    this.#bindAdmissionUser(userEntryId, turnId);\n    const draftId = (this.#turnWaiter as TurnWaiter | null)?.draftId ?? null;\n    const draft =\n      draftId === null ? undefined : this.#transcript.find((entry) => entry.id === draftId);\n    if (draft !== undefined && draft.turnId === null) draft.turnId = turnId;\n    try {\n      await this.#persist();\n    } catch (error) {\n      this.#rejectTurn(error);\n      this.#releaseTurnAdmission(admission);\n      await terminal.catch(() => undefined);","sourceCodeStart":1565,"sourceCodeEnd":1601,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/live/live-session.ts#L1565-L1601","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (test stub)\n{ turn: {} } // omitted turn.id -> throws\n// after\n{ turn: { id: 'turn_123', status: 'running' } }","handlingStrategy":"validation","validationCode":"const turn = (response as { turn?: { id?: unknown } }).turn;\nif (typeof turn?.id !== 'string' || turn.id.length === 0) throw new Error('turn.start response missing turn.id');","typeGuard":"function hasTurnId(r: unknown): r is { turn: { id: string } } {\n  const t = (r as any)?.turn;\n  return !!t && typeof t.id === 'string' && t.id.length > 0;\n}","tryCatchPattern":"try {\n  await session.sendMessage(msg);\n} catch (e) {\n  if ((e as Error).message === 'Codex turn response omitted turn.id') {\n    // inspect raw response; verify adapter/Codex versions before retry\n  } else throw e;\n}","preventionTips":["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"],"tags":["protocol","response-shape","codex"],"backgroundTag":"unexpected-response-shape","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}