openclaw/openclaw · error

Codex settled-turn finalization returned unexpected native i

Error message

Codex settled-turn finalization returned unexpected native item: ${unexpectedItem.type}

What it means

Thrown when iterating the finalizer's bounded-turn output items and encountering an item whose type is not in FINALIZER_PASSIVE_ITEM_TYPES (agentMessage, reasoning) and not the prompt-echo userMessage. The finalizer is instructed to produce a single text answer with no external capabilities (requireNoExternalCapabilities: true), so any function_call, tool call, or stray userMessage is treated as a contract violation.

Source

Thrown at extensions/codex/src/app-server/settled-turn-finalizer.ts:80

    }
    if (item.type === "userMessage" && !promptEchoSeen) {
      const content = Array.isArray(item.content) ? item.content : [];
      const input = content[0];
      const isPromptEcho =
        content.length === 1 &&
        isJsonObject(input) &&
        input.type === "text" &&
        input.text === attempt.prompt;
      if (isPromptEcho) {
        promptEchoSeen = true;
        continue;
      }
    }
    unexpectedItem = item;
    break;
  }
  if (unexpectedItem) {
    throw new Error(
      `Codex settled-turn finalization returned unexpected native item: ${unexpectedItem.type}`,
    );
  }
  const text = bounded.text.trim();
  if (!text) {
    return {
      assistant: createAssistantMessage(attempt, "", {
        tokenUsage: bounded.usage,
        aborted: false,
        promptError: null,
      }),
      ...(bounded.usage ? { usage: bounded.usage } : {}),
    };
  }
  if (isSilentReplyText(text)) {
    throw new Error("Codex settled-turn finalization completed without a visible answer");
  }

View on GitHub (pinned to 01804a7531)

Solutions

  1. Inspect bounded.items to see the unexpected item type and payload; the message includes the type.
  2. Confirm the bounded turn was launched with requireNoExternalCapabilities: true and isolation: "private-stdio".
  3. If the protocol added a new passive item type, add it to FINALIZER_PASSIVE_ITEM_TYPES after confirming it carries no executable capability.
  4. Tighten FINALIZER_DEVELOPER_INSTRUCTIONS or switch model if the finalizer persistently emits tool calls.

Example fix

// before
const FINALIZER_PASSIVE_ITEM_TYPES = new Set(["agentMessage", "reasoning"]);
// item.type === "function_call" -> throws

// after (protocol added reasoning summary, verified non-executable)
const FINALIZER_PASSIVE_ITEM_TYPES = new Set(["agentMessage", "reasoning", "reasoningSummary"]);
Defensive patterns

Strategy: validation

Validate before calling

const FINALIZER_ALLOWED_ITEM_TYPES = new Set(["agentMessage", "reasoning", "userMessage"]);

function assertFinalizerItemsAcceptable(items: ReadonlyArray<{ type: string }>): void {
  for (const item of items) {
    if (!FINALIZER_ALLOWED_ITEM_TYPES.has(item.type)) {
      throw new Error(`Finalizer produced disallowed item type up front: ${item.type}`);
    }
  }
}

// run after bounded.items returns, before runCodexSettledTurnFinalization proceeds
assertFinalizerItemsAcceptable(bounded.items);

Type guard

function isPassiveFinalizerItem(item: { type: string }): boolean {
  return item.type === "agentMessage" || item.type === "reasoning";
}

function isPromptEchoUserMessage(item: { type: string; content?: unknown }, prompt: string): boolean {
  if (item.type !== "userMessage" || !Array.isArray(item.content) || item.content.length !== 1) return false;
  const c = item.content[0] as { type?: string; text?: unknown };
  return c?.type === "text" && c.text === prompt;
}

Try / catch

try {
  return await runCodexSettledTurnFinalization(operation, options);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Codex settled-turn finalization returned unexpected native item")) {
    // The model ignored requireNoExternalCapabilities; re-run with stricter instructions or different model.
    logger.error({ itemType: err.message }, "finalizer produced unexpected item");
  }
  throw err;
}

Prevention

When it happens

Trigger: The finalizer model emits a function_call or function_call_output despite requireNoExternalCapabilities; the model echoes something other than the prompt as a userMessage; a reasoning/agentMessage item is missing its type tag due to a protocol parsing drift.

Common situations: Model regression where the finalizer ignores developer instructions and tries to call a tool; app-server protocol change that renames an item type; prompt that the model parrots back in a non-echo userMessage slot.

Related errors


AI-assisted analysis of openclaw/openclaw@01804a7531 (2026-08-12). Data as JSON: /api/errors/5a24b8d800c0d381. Report an issue: GitHub.