openclaw - 💡(How to fix) Fix [Bug]: @openclaw/codex hardcodes features.code_mode_only=true, stalling every tool-using Codex-runtime turn (2026.5.10-beta.5+)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

After upgrading from 2026.5.2 to 2026.5.12, every Codex-runtime agent turn that needs to call a tool stalls forever; the codex_app_server emits custom_tool_call items (with JS bodies) marked status: "completed" but no task_complete follows, because @openclaw/codex hard-overrides user config and forces features.code_mode: true + features.code_mode_only: true into every thread it starts.

Root Cause

After upgrading from 2026.5.2 to 2026.5.12, every Codex-runtime agent turn that needs to call a tool stalls forever; the codex_app_server emits custom_tool_call items (with JS bodies) marked status: "completed" but no task_complete follows, because @openclaw/codex hard-overrides user config and forces features.code_mode: true + features.code_mode_only: true into every thread it starts.

Fix Action

Fix / Workaround

Local mitigation that immediately restored chat replies (patched plugin dist + gateway restart)

$ sed -i.bak -e 's#"features.code_mode": true#"features.code_mode": false#g'
-e 's#"features.code_mode_only": true#"features.code_mode_only": false#g'
~/.openclaw/npm/node_modules/@openclaw/codex/dist/thread-lifecycle-CJppEyYT.js $ openclaw gateway restart $ openclaw agent --agent main --message "Use exec_command to run 'echo hello-from-tool' and report the result." hello-from-tool

No further stalled session diagnostics observed in the 9 minutes following the restart.


- Last known good: `@openclaw/[email protected]` (stable). First known bad: `@openclaw/[email protected]`.
- Originating change: #80001 ("Enable Codex native code mode for OpenClaw harness runs", `0e8a7e12da`).
- Workaround until a fix lands: patch `dist/thread-lifecycle-*.js` to flip both feature flags to `false` and restart the gateway. The patch needs to be re-applied after every plugin upgrade.
- Suggested fix shapes (happy to send a PR once a maintainer picks one):
  1. Flip the two flags to `false` by default and expose an opt-in (via `openclaw.json` `agents.defaults` or per-model `agentRuntime.options`) so power users can keep `code_mode` on.
  2. Change the merge order in `buildCodexRuntimeThreadConfig` to `mergeCodexThreadConfigs(CODEX_CODE_MODE_THREAD_CONFIG, config)` so the existing config path can override at all — independent of which default we ship.
  3. Keep `code_mode: true` but disable `code_mode_only`, if the intent of #80001 was to make code-mode available without forcing it as the only tool surface.
- Filed with AI assistance (Cursor agent paired session); evidence captured live on the affected machine.

Code Example

{
     "agents": {
       "agents": {
         "main": { "models": { "primary": "openai/gpt-5.5" } }
       }
     },
     "models": {
       "models": {
         "openai/gpt-5.5": { "alias": "main", "agentRuntime": { "id": "codex" } }
       }
     }
   }

---

export const CODEX_CODE_MODE_THREAD_CONFIG: JsonObject = {
  "features.code_mode": true,
  "features.code_mode_only": true,
};

// ...
export function buildCodexRuntimeThreadConfig(config: JsonObject | undefined): JsonObject {
  const runtimeConfig = mergeCodexThreadConfigs(config, CODEX_CODE_MODE_THREAD_CONFIG) ?? {
    ...CODEX_CODE_MODE_THREAD_CONFIG,
  };
  return runtimeConfig;
}

---

{"timestamp":"2026-05-16T19:12:45.171Z","type":"response_item","payload":{"type":"custom_tool_call","status":"completed","call_id":"call_wfIluEH7I6TLJmP5gZlnRi8t","name":"exec","input":"await tools.message({action:\"send\", message:\"Hello, Wass. I’m here now.\"});"}}

---

"models": {
  "models": {
    "openai/gpt-5.5": { "alias": "main", "agentRuntime": { "id": "codex" } }
  }
}

---

# gateway.err.log — typical recurring entry for a stalled Codex-runtime turn
2026-05-16T13:58:58.134-04:00 [diagnostic] stalled session: sessionId=<redacted> sessionKey=agent:main:telegram:direct:<redacted> state=processing age=199s queueDepth=1 reason=active_work_without_progress classification=stalled_agent_run activeWorkKind=embedded_run lastProgress=codex_app_server:notification:thread/tokenUsage/updated lastProgressAge=199s recovery=none

# Same session's rollout JSONL — sole agent action of the turn
{"timestamp":"2026-05-16T18:34:17.525Z","type":"response_item","payload":{"type":"custom_tool_call","status":"completed","call_id":"call_PnLYAYMQmjpV5PLnNsxSYcIf","name":"exec","input":"await tools.message({action:\"send\", message:\"Here, Wass. I’m back.\"});"}}

# Plugin dist confirming the hardcoded enable (line numbers from npm tarball)
$ rg -n '"features.code_mode' ~/.openclaw/npm/node_modules/@openclaw/codex/dist
dist/thread-lifecycle-CJppEyYT.js:680:	"features.code_mode": true,
dist/thread-lifecycle-CJppEyYT.js:681:	"features.code_mode_only": true

# Local mitigation that immediately restored chat replies (patched plugin dist + gateway restart)
$ sed -i.bak -e 's#"features.code_mode": true#"features.code_mode": false#g' \
             -e 's#"features.code_mode_only": true#"features.code_mode_only": false#g' \
  ~/.openclaw/npm/node_modules/@openclaw/codex/dist/thread-lifecycle-CJppEyYT.js
$ openclaw gateway restart
$ openclaw agent --agent main --message "Use exec_command to run 'echo hello-from-tool' and report the result."
hello-from-tool
# No further `stalled session` diagnostics observed in the 9 minutes following the restart.
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

After upgrading from 2026.5.2 to 2026.5.12, every Codex-runtime agent turn that needs to call a tool stalls forever; the codex_app_server emits custom_tool_call items (with JS bodies) marked status: "completed" but no task_complete follows, because @openclaw/codex hard-overrides user config and forces features.code_mode: true + features.code_mode_only: true into every thread it starts.

Steps to reproduce

  1. Install OpenClaw 2026.5.12 (bundles @openclaw/[email protected], which depends on @openai/[email protected]).
  2. Configure a Codex-runtime agent. Minimal config:
    {
      "agents": {
        "agents": {
          "main": { "models": { "primary": "openai/gpt-5.5" } }
        }
      },
      "models": {
        "models": {
          "openai/gpt-5.5": { "alias": "main", "agentRuntime": { "id": "codex" } }
        }
      }
    }
  3. Send any message that requires the agent to invoke a tool. Easiest repro: openclaw agent --agent main --message "Use exec_command to run 'echo hi' and report the result.".
  4. Observe that the CLI never returns. gateway.err.log shows [diagnostic] stalled session ... reason=active_work_without_progress classification=stalled_agent_run activeWorkKind=embedded_run lastProgress=codex_app_server:notification:thread/tokenUsage/updated every 30 s indefinitely.
  5. Inspect the rollout file under agents/<agent>/agent/codex-home/sessions/.../rollout-*.jsonl. The agent's response_item is a custom_tool_call with name:"exec" and a JS string (e.g. await tools.message({action:"send", message:"..."});), marked status:"completed" by codex, but no follow-up task_complete is ever recorded.

Bisect of @openclaw/codex package on npm:

  • 2026.5.10features.code_mode not present in dist; chat replies work.
  • 2026.5.10-beta.5 — first version where dist/thread-lifecycle-*.js contains "features.code_mode": true, "features.code_mode_only": true. Stalls begin here.
  • Every published version through 2026.5.16-beta.2 carries the same hardcoded enable.

Source: introduced by #80001 (Enable Codex native code mode for OpenClaw harness runs, commit 0e8a7e12da), extensions/codex/src/app-server/thread-lifecycle.ts:

export const CODEX_CODE_MODE_THREAD_CONFIG: JsonObject = {
  "features.code_mode": true,
  "features.code_mode_only": true,
};

// ...
export function buildCodexRuntimeThreadConfig(config: JsonObject | undefined): JsonObject {
  const runtimeConfig = mergeCodexThreadConfigs(config, CODEX_CODE_MODE_THREAD_CONFIG) ?? {
    ...CODEX_CODE_MODE_THREAD_CONFIG,
  };
  return runtimeConfig;
}

mergeCodexThreadConfigs iterates left-to-right and overwrites earlier keys with later ones, so CODEX_CODE_MODE_THREAD_CONFIG wins over any user-supplied config. There is no openclaw.json knob, env var, or per-agent override that can turn these flags off — verified by grep across the plugin dist and against the source tree at main (HEAD = 9e038656).

Expected behavior

In 2026.5.2 (and @openclaw/[email protected], the last release before the flag was hardcoded on), Codex-runtime agents complete tool-using turns: the model emits a normal function_call (e.g. functions.exec_command), OpenClaw runs the tool, hands the result back to codex, and the turn closes with task_complete. No stalled-session diagnostics are produced.

Actual behavior

After upgrading to 2026.5.12:

  • Listing tools ("List the names of all tools available to you, one per line.") returns a normal-looking tool list (the snippet rendered to the user), but the underlying codex thread is configured with features.code_mode_only: true, so the model can only call a synthetic JS-eval tool.
  • Any prompt that requires tool use produces a custom_tool_call response_item with name:"exec" and a JS body invoking tools.<name>(...). Example from a real Telegram session rollout:
    {"timestamp":"2026-05-16T19:12:45.171Z","type":"response_item","payload":{"type":"custom_tool_call","status":"completed","call_id":"call_wfIluEH7I6TLJmP5gZlnRi8t","name":"exec","input":"await tools.message({action:\"send\", message:\"Hello, Wass. I’m here now.\"});"}}
  • codex_app_server marks the item status:"completed" internally but no task_complete event reaches the OpenClaw host. The session stays in state=processing indefinitely.
  • Telegram inbound messages queue behind the wedged session, so the channel goes silent until the gateway is killed.
  • Prompts that do not require tools (e.g. "Reply with exactly the word pong") complete normally, which masks the bug from simple connectivity probes.

OpenClaw version

2026.5.12 (f066dd2), @openclaw/[email protected], @openai/[email protected]

Operating system

macOS 12.7.6 (x86_64), Node 24.14.0

Install method

npm global (pnpm channel per openclaw status)

Model

openai/gpt-5.5

Provider / routing chain

openclawopenai provider (default base URL) → resolved through codex agent runtime via openAIProviderUsesCodexRuntimeByDefaultcodex_app_server (@openai/[email protected])

Additional provider/model setup details

openclaw.json declares:

"models": {
  "models": {
    "openai/gpt-5.5": { "alias": "main", "agentRuntime": { "id": "codex" } }
  }
}

No custom baseUrl is set, so OpenClaw's openAIProviderUsesCodexRuntimeByDefault routes the model through the embedded codex runtime. Auth profile uses mode: oauth; ~/.codex/auth.json is apikey, but the bug reproduces regardless of which credential is in effect (turn never reaches a token-failure path).

Logs, screenshots, and evidence

# gateway.err.log — typical recurring entry for a stalled Codex-runtime turn
2026-05-16T13:58:58.134-04:00 [diagnostic] stalled session: sessionId=<redacted> sessionKey=agent:main:telegram:direct:<redacted> state=processing age=199s queueDepth=1 reason=active_work_without_progress classification=stalled_agent_run activeWorkKind=embedded_run lastProgress=codex_app_server:notification:thread/tokenUsage/updated lastProgressAge=199s recovery=none

# Same session's rollout JSONL — sole agent action of the turn
{"timestamp":"2026-05-16T18:34:17.525Z","type":"response_item","payload":{"type":"custom_tool_call","status":"completed","call_id":"call_PnLYAYMQmjpV5PLnNsxSYcIf","name":"exec","input":"await tools.message({action:\"send\", message:\"Here, Wass. I’m back.\"});"}}

# Plugin dist confirming the hardcoded enable (line numbers from npm tarball)
$ rg -n '"features.code_mode' ~/.openclaw/npm/node_modules/@openclaw/codex/dist
dist/thread-lifecycle-CJppEyYT.js:680:	"features.code_mode": true,
dist/thread-lifecycle-CJppEyYT.js:681:	"features.code_mode_only": true

# Local mitigation that immediately restored chat replies (patched plugin dist + gateway restart)
$ sed -i.bak -e 's#"features.code_mode": true#"features.code_mode": false#g' \
             -e 's#"features.code_mode_only": true#"features.code_mode_only": false#g' \
  ~/.openclaw/npm/node_modules/@openclaw/codex/dist/thread-lifecycle-CJppEyYT.js
$ openclaw gateway restart
$ openclaw agent --agent main --message "Use exec_command to run 'echo hello-from-tool' and report the result."
hello-from-tool
# No further `stalled session` diagnostics observed in the 9 minutes following the restart.

Impact and severity

  • Affected: every user on @openclaw/codex >=2026.5.10-beta.5 (so 2026.5.10-beta.5 through 2026.5.16-beta.2, including the current stable 2026.5.12) whose agents are configured for the codex runtime. That includes the default openai/<model> + agentRuntime: { id: "codex" } setup the upgrade wizard now produces.
  • Severity: High. Every tool-using turn hangs; Telegram and other channels stop replying because the session lane is stuck in state=processing.
  • Frequency: 100% on tool-using turns. Non-tool turns appear to work, which makes the regression easy to misdiagnose as connectivity flakiness.
  • Consequence: Channels go silent (Telegram messages observed queued behind stalled sessions for >18 minutes until manual gateway restart); user-visible symptom is "agent stopped responding after upgrading to 2026.5.12".

Additional information

  • Last known good: @openclaw/[email protected] (stable). First known bad: @openclaw/[email protected].
  • Originating change: #80001 ("Enable Codex native code mode for OpenClaw harness runs", 0e8a7e12da).
  • Workaround until a fix lands: patch dist/thread-lifecycle-*.js to flip both feature flags to false and restart the gateway. The patch needs to be re-applied after every plugin upgrade.
  • Suggested fix shapes (happy to send a PR once a maintainer picks one):
    1. Flip the two flags to false by default and expose an opt-in (via openclaw.json agents.defaults or per-model agentRuntime.options) so power users can keep code_mode on.
    2. Change the merge order in buildCodexRuntimeThreadConfig to mergeCodexThreadConfigs(CODEX_CODE_MODE_THREAD_CONFIG, config) so the existing config path can override at all — independent of which default we ship.
    3. Keep code_mode: true but disable code_mode_only, if the intent of #80001 was to make code-mode available without forcing it as the only tool surface.
  • Filed with AI assistance (Cursor agent paired session); evidence captured live on the affected machine.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

In 2026.5.2 (and @openclaw/[email protected], the last release before the flag was hardcoded on), Codex-runtime agents complete tool-using turns: the model emits a normal function_call (e.g. functions.exec_command), OpenClaw runs the tool, hands the result back to codex, and the turn closes with task_complete. No stalled-session diagnostics are produced.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: @openclaw/codex hardcodes features.code_mode_only=true, stalling every tool-using Codex-runtime turn (2026.5.10-beta.5+)