paperclipai/paperclip · error · HarnessReconciliationError

codex_history_incomplete

codex_history_incomplete

Error message

codex_history_incomplete: ${method} omitted data

What it means

pages() requires every page response from the history RPC to contain a data array. When the provider omits the data field, the library throws HarnessReconciliationError with code codex_history_incomplete rather than treating the missing data as an empty page, since a partial read cannot prove the thread is idle.

Source

Thrown at packages/paperclip-runner/src/drivers/codex/codex-history.ts:31

): Promise<Record<string, unknown>[]> {
  const values = new Map<string, Record<string, unknown>>();
  const cursors = new Set<string>();
  let cursor: string | undefined;
  for (let page = 0; page < 10_000; page += 1) {
    let response: Record<string, unknown>;
    try {
      response = await transport.request(method, {
        ...params,
        limit: 100,
        ...(cursor ? { cursor } : {}),
      });
    } catch (error) {
      throw new HarnessReconciliationError(
        `codex_history_read_failed: ${method} requires supported paginated history; ${String(error)}`,
      );
    }
    if (!Array.isArray(response.data))
      throw new HarnessReconciliationError(
        `codex_history_incomplete: ${method} omitted data`,
      );
    for (const raw of response.data) {
      const value = record(raw);
      const id = identity(value);
      if (!id)
        throw new HarnessReconciliationError(
          `codex_history_incomplete: ${method} omitted an identity`,
        );
      // Later pages can repeat the cursor anchor with its newly completed state.
      values.set(id, value);
    }
    const next = response.nextCursor;
    if (next == null) return [...values.values()];
    if (typeof next !== "string" || !next || cursors.has(next)) {
      throw new HarnessReconciliationError(
        `codex_history_incomplete: ${method} repeated or invalid cursor`,
      );

View on GitHub (pinned to 01ad858492)

Solutions

  1. Pin or upgrade the Codex app-server to a version whose list methods return { data, nextCursor } envelopes.
  2. Log the full raw response to confirm the actual envelope shape and compare against the expected app-server protocol.
  3. If a proxy/wrapper sits in front of the app-server, fix it to pass through the response unchanged.
  4. Catch HarnessReconciliationError and fail the recovery run; never assume an empty history on this error.
Defensive patterns

Strategy: try-catch

Type guard

function isHistoryIncomplete(e: unknown): e is HarnessReconciliationError { return e instanceof HarnessReconciliationError && e.message.includes('codex_history_incomplete'); }

Try / catch

try { const turns = await readCodexTurnMetadata(transport, threadId); } catch (e) { if (isHistoryIncomplete(e)) { reportReconciliationFailure(e); return null; } throw e; }

Prevention

When it happens

Trigger: A thread/turns/list or thread/items/list response object has no array-valued data field — e.g. an app-server version returning a different envelope shape, or an error object returned as a successful response.

Common situations: Codex app-server API drift: a provider upgrade changed the response contract; a proxy or middleware stripping/renaming fields; mocking layers returning wrong shapes in tests.

Related errors


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