openclaw - ✅(Solved) Fix [Bug]: (payloads=0) when using OpenRouter [2 pull requests, 1 comments, 2 participants]

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…
GitHub stats
openclaw/openclaw#68030Fetched 2026-04-18 05:54:20
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
0
Timeline (top)
labeled ×2commented ×1cross-referenced ×1

I just installed Claw, i got my key for OpenRouter but when I try to chat inside the dashboard it does not respond. And on the terminal I get (payload=0). I've tred for hours to "debug" along side Chat and Claude and this is the respond I got

Chat: Final Diagnosis (100% confirmed)

You are fully set up correctly now.

But you are still getting:

payloads=0

👉 That means:

OpenClaw 2026.4.15 cannot parse OpenRouter responses reliably

Not:

your API key ❌ your config ❌ your credits ❌ your model choice ❌

👉 This is a hard compatibility bug

Claude: You're already on the latest version (2026.4.15). Here's the situation:

The error is in openclaw's closed/bundled code — it's not something you can directly patch. The logic at line 9597 of [pi-embedded-runner-DN0VbqlW.js](vscode-webview://****** fires when the model returns a stop response with zero usable payloads, after exhausting retry attempts.

What you can try:

Likely transient — empty responses from Claude via OpenRouter happen occasionally; retrying the same prompt usually works Switch model — in [openclaw.json](vscode-webview://***** you have openrouter/auto configured as an alias; trying it as the primary model might route around flaky responses Report it — if it's happening consistently with a specific prompt/flow, file an issue with the openclaw project so they can improve the retry logic The error itself is surfaced correctly by openclaw — it's not silently failing, just telling you the agent got an empty response it couldn't recover from.

Error Message

The error is in openclaw's closed/bundled code — it's not something you can directly patch. The logic at line 9597 of [pi-embedded-runner-DN0VbqlW.js](vscode-webview://****** fires when the model returns a stop response with zero usable payloads, after exhausting retry attempts. The error itself is surfaced correctly by openclaw — it's not silently failing, just telling you the agent got an empty response it couldn't recover from.

Root Cause

I just installed Claw, i got my key for OpenRouter but when I try to chat inside the dashboard it does not respond. And on the terminal I get (payload=0). I've tred for hours to "debug" along side Chat and Claude and this is the respond I got

Chat: Final Diagnosis (100% confirmed)

You are fully set up correctly now.

But you are still getting:

payloads=0

👉 That means:

OpenClaw 2026.4.15 cannot parse OpenRouter responses reliably

Not:

your API key ❌ your config ❌ your credits ❌ your model choice ❌

👉 This is a hard compatibility bug

Claude: You're already on the latest version (2026.4.15). Here's the situation:

The error is in openclaw's closed/bundled code — it's not something you can directly patch. The logic at line 9597 of [pi-embedded-runner-DN0VbqlW.js](vscode-webview://****** fires when the model returns a stop response with zero usable payloads, after exhausting retry attempts.

What you can try:

Likely transient — empty responses from Claude via OpenRouter happen occasionally; retrying the same prompt usually works Switch model — in [openclaw.json](vscode-webview://***** you have openrouter/auto configured as an alias; trying it as the primary model might route around flaky responses Report it — if it's happening consistently with a specific prompt/flow, file an issue with the openclaw project so they can improve the retry logic The error itself is surfaced correctly by openclaw — it's not silently failing, just telling you the agent got an empty response it couldn't recover from.

Fix Action

Fix / Workaround

The error is in openclaw's closed/bundled code — it's not something you can directly patch. The logic at line 9597 of [pi-embedded-runner-DN0VbqlW.js](vscode-webview://****** fires when the model returns a stop response with zero usable payloads, after exhausting retry attempts.

PR fix notes

PR #68351: fix(openrouter): surface reasoning_details visible-text as user output (#68261)

Description (problem / solution / changelog)

Summary

  • Problem: OpenRouter model runs (e.g. openrouter/google/gemini-2.5-flash, Grok 4.x, minimax-m2.7) return blank responses with stopReason=stop payloads=0 and surface ⚠️ Agent couldn't generate a response.
  • Why it matters: Entire classes of OpenRouter-proxied models have been unusable since 2026.4.14/15 despite healthy gateway and successful upstream responses.
  • What changed: getCompletionsReasoningDelta in src/agents/openai-transport-stream.ts now discriminates the OpenRouter reasoning_details stream between hidden reasoning (reasoning.text) and OpenAI Responses–style visible output (response.output_text, response.text, text). Visible-output items are routed through the same text-block path as choice.delta.content instead of being buried in a thinking block.
  • What did NOT change (scope boundary): no changes to prompts, auth, sandbox, tool policy, secret handling, provider routing, request assembly, transcript bytes, or prompt-cache order. Previous reasoning.text behavior is preserved byte-for-byte.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #68261
  • Related #67410, #67575, #67698, #67907, #67425, #68030, #68076, #68185
  • This PR fixes a bug or regression

Root Cause

e0bf756b50 ("fix: handle OpenRouter Qwen3 reasoning_details streams") taught getCompletionsReasoningDelta to parse reasoning_details items, but it unconditionally classified every matching item as hidden thinking. Some OpenRouter upstreams (Gemini 2.5 Flash via the Responses-style reasoning proxy, xAI Grok 4.x, and related models) deliver the assistant's final answer inside reasoning_details using OpenAI Responses content types such as response.output_text, response.text, and plain text, with an empty choice.delta.content. Because the parser treated those as thinking, the stream closed with stopReason=stop, zero text blocks, and the incomplete-turn detector in src/agents/pi-embedded-runner/run/incomplete-turn.ts surfaced the generic error.

  • Root cause: reasoning_details visible-output types were misclassified as internal reasoning and never emitted as user-visible text.
  • Missing detection / guardrail: no regression covered reasoning_details streams where the final answer arrives without a separate content field.
  • Contributing context: OpenRouter's proxy layer for several reasoning models started folding visible output into reasoning_details alongside reasoning bytes.

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
  • Target test or file: src/agents/openai-transport-stream.test.ts
  • Scenario the test should lock in: a mixed reasoning_details stream where reasoning.text items stay as thinking while response.output_text, response.text, and text items surface as a user-visible text block with stopReason=stop.
  • Why this is the smallest reliable guardrail: it exercises the exact parser path that decides whether bytes become visible text or hidden thinking.
  • Existing test that already covers this: handles reasoning_details from OpenRouter/Qwen3 in completions stream only covered content + reasoning.text mixes, not the visible-text-in-reasoning_details case.

User-visible / Behavior Changes

  • OpenRouter models that deliver the final answer inside reasoning_details (e.g. Gemini 2.5 Flash, Grok 4.x) now produce visible replies instead of the generic ⚠️ Agent couldn't generate a response error. No configuration, defaults, or docs change.

Diagram

Before:
OpenRouter -> reasoning_details[{type:"response.output_text", text:"hello"}]
           -> classified as thinking
           -> stopReason=stop, payloads=0
           -> "⚠️ Agent couldn't generate a response."

After:
OpenRouter -> reasoning_details[{type:"response.output_text", text:"hello"}]
           -> classified as visible text
           -> text block "hello", stopReason=stop, payloads>=1
           -> user sees "hello"

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Runtime-enforced controls that are explicitly unchanged by this PR: tool policy/allowlist, sandbox, exec approval, subagent policy, secrets plan, owner-only gating, OpenRouter routing, auth profiles, and prompt-cache request assembly. The fix is confined to classification of bytes the upstream already returned over an authenticated, already-policy-gated channel; it does not rely on or modify any prompt text or runtime policy. A malicious upstream that labels reasoning as type: "text" cannot leak more than it could by setting choice.delta.content directly, which is already the default visible path.

Repro + Verification

Environment

  • OS: macOS (Darwin 25.3.0)
  • Runtime/container: local OpenClaw gateway (loopback)
  • Model/provider: openrouter/google/gemini-2.5-flash, openrouter/x-ai/grok-4.1-fast, openrouter/minimax/minimax-m2.7
  • Integration/channel: none (direct openclaw infer model run) and dashboard
  • Relevant config: agents.defaults.models = { "openrouter/google/gemini-2.5-flash": {} } (redacted)

Steps

  1. openclaw infer model run --model openrouter/google/gemini-2.5-flash --prompt "Reply with exactly: hello" --json
  2. Observe response contents and gateway log for incomplete turn detected ... payloads=0.
  3. Repeat for Grok 4.x / minimax-m2.7.

Expected

  • outputs[0].text contains the assistant reply.
  • No payloads=0 / incomplete turn detected warning.

Actual (before fix)

  • outputs[0].text = ⚠️ Agent couldn't generate a response. Please try again.
  • Gateway log: incomplete turn detected: ... stopReason=stop payloads=0 — surfacing error to user.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets

Before: reasoning_details visible-text items classified as thinking, zero text blocks, stopReason=stop payloads=0. After: new test surfaces reasoning_details visible-text as text while keeping reasoning.text as thinking asserts text block emission alongside the preserved thinking block; existing reasoning_details/Qwen3 and tool-call regression tests remain green.

Human Verification (required)

  • Verified scenarios:
    • pnpm test src/agents/openai-transport-stream.test.ts — 56/56 pass including the new case.
    • pnpm test src/agents/openai-transport-stream.test.ts -t reasoning_details — 4/4 reasoning_details cases pass.
    • Re-ran pnpm check (host-env-policy, tool-display, no-conflict-markers green); remaining pnpm tsgo/pnpm lint failures are pre-existing in extensions/qa-lab/src/providers/aimock/server.ts on upstream/main and unrelated to this change (verified by running pnpm tsgo on clean upstream/main).
  • Edge cases checked:
    • reasoning.text-only stream still becomes a thinking block (existing Qwen3 test).
    • Mixed reasoning.text + visible-text items in the same stream produce both thinking and text blocks in order.
    • reasoning_details arriving alongside tool_calls still routes through the buffered thinking path and preserves tool-call arguments (existing tests).
    • Non-array or unknown-type reasoning_details items are skipped silently.
  • What I did not verify:
    • Live OpenRouter run against real keys (no live lane invoked in this change).
    • Parallels smoke / cross-platform onboarding (not in scope for a parser-only fix).

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: a model intentionally using type: "text" inside reasoning_details for genuinely-hidden scratchpad content would now surface that content to users.
    • Mitigation: OpenRouter's documented semantics for response.output_text / response.text / text are visible assistant output; the existing reasoning.text type still maps to hidden reasoning. If a specific upstream deviates, follow-up can narrow the visible-type set.
  • Risk: Qwen3 regression from #66905 returns.
    • Mitigation: the existing Qwen3 regression test and the tool-call + reasoning_details test remain unchanged and still pass.

Testing notes

  • AI-assisted PR, lightly tested (parser unit tests only; no live OpenRouter run).
  • Exact tests run:
    • pnpm test src/agents/openai-transport-stream.test.ts (56/56 pass)
    • pnpm test src/agents/openai-transport-stream.test.ts -t reasoning_details (4/4 pass)
    • pnpm test src/agents/openai-transport-stream.test.ts -t visible-text (1/1 pass)
    • pnpm check (pre-existing aimock/server.ts failures on upstream/main; no new failures introduced)

Made with Cursor

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/openai-transport-stream.test.ts (modified, +138/-0)
  • src/agents/openai-transport-stream.ts (modified, +63/-14)

PR #68574: fix(openrouter): heal stale provider base urls

Description (problem / solution / changelog)

Summary

  • Problem: OpenRouter and Arcee could persist or keep using the stale https://openrouter.ai/v1 route in provider config or discovered model metadata.
  • Why it matters: that stale route breaks OpenRouter-routed requests and makes fresh models.json writes plus older discovered rows keep failing until the user manually edits config.
  • What changed: OpenRouter and Arcee now canonicalize stale OpenRouter base URLs during provider config normalization, runtime transport normalization, and resolved-model normalization; the embedded-runner regression support and tests were updated to cover the self-heal path.
  • What did NOT change (scope boundary): this PR does not touch OpenRouter reasoning_details parsing, alias resolution like openrouter:free, or generic incomplete-turn handling outside the stale-baseUrl bucket.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause (if applicable)

  • Root cause: provider-owned OpenRouter paths were missing the same canonical baseUrl normalization already used for stale Codex transport metadata, so legacy https://openrouter.ai/v1 values could survive config writes and runtime model resolution.
  • Missing detection / guardrail: no provider-level regression test covered stale OpenRouter /v1 metadata on either plugin normalization or embedded model resolution.
  • Contributing context (if known): multiple OpenRouter bug reports were collapsed into the same payloads=0 symptom even though some were really stale route/config drift rather than stream parser bugs.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/openrouter/index.test.ts, extensions/arcee/index.test.ts, src/agents/pi-embedded-runner/model.test.ts
  • Scenario the test should lock in: stale https://openrouter.ai/v1 config or discovered model metadata is rewritten to https://openrouter.ai/api/v1 before runtime uses it.
  • Why this is the smallest reliable guardrail: the bug lives in provider normalization seams plus embedded model resolution, so plugin tests alone were not enough.
  • Existing test that already covers this (if any): the Codex stale transport coverage was the closest prior pattern.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • OpenRouter-backed configs and discovered model rows now self-heal from https://openrouter.ai/v1 to https://openrouter.ai/api/v1.
  • Arcee models routed through OpenRouter get the same canonicalization instead of keeping a stale route.

Diagram (if applicable)

Before:
[stale models.json/discovered row] -> https://openrouter.ai/v1 -> broken OpenRouter-routed request

After:
[stale models.json/discovered row] -> provider normalize hooks -> https://openrouter.ai/api/v1 -> request works

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local dev worktree
  • Model/provider: OpenRouter, Arcee-via-OpenRouter
  • Integration/channel (if any): N/A
  • Relevant config (redacted): stale provider baseUrl: https://openrouter.ai/v1

Steps

  1. Configure OpenRouter or Arcee with a stale OpenRouter base URL (https://openrouter.ai/v1).
  2. Resolve provider config or discovered model metadata through the normal plugin/runtime path.
  3. Attempt to use the resolved transport.

Expected

  • The provider canonicalizes the stale route to https://openrouter.ai/api/v1 before use.

Actual

  • The stale /v1 route persisted and continued breaking OpenRouter-routed requests.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: ran pnpm test:serial extensions/openrouter/index.test.ts extensions/arcee/index.test.ts src/agents/pi-embedded-runner/model.test.ts and confirmed plugin-level plus embedded-resolution canonicalization.
  • Edge cases checked: trailing slash on stale /v1/, OpenRouter runtime rows, Arcee OpenRouter rows that also need vendor-prefix normalization.
  • What you did not verify: live OpenRouter traffic against a real key.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: a non-OpenRouter custom proxy that intentionally uses https://openrouter.ai/v1 semantics could get canonicalized.
    • Mitigation: normalization is limited to explicit OpenRouter-owned provider hooks and only rewrites the known stale OpenRouter host/path pair.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/arcee/index.test.ts (modified, +44/-0)
  • extensions/arcee/index.ts (modified, +29/-12)
  • extensions/arcee/provider-catalog.ts (modified, +13/-1)
  • extensions/openrouter/index.test.ts (modified, +48/-0)
  • extensions/openrouter/index.ts (modified, +32/-2)
  • extensions/openrouter/provider-catalog.ts (modified, +17/-1)
  • src/agents/pi-embedded-runner/model.provider-runtime.test-support.ts (modified, +29/-0)
  • src/agents/pi-embedded-runner/model.test.ts (modified, +29/-0)
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

I just installed Claw, i got my key for OpenRouter but when I try to chat inside the dashboard it does not respond. And on the terminal I get (payload=0). I've tred for hours to "debug" along side Chat and Claude and this is the respond I got

Chat: Final Diagnosis (100% confirmed)

You are fully set up correctly now.

But you are still getting:

payloads=0

👉 That means:

OpenClaw 2026.4.15 cannot parse OpenRouter responses reliably

Not:

your API key ❌ your config ❌ your credits ❌ your model choice ❌

👉 This is a hard compatibility bug

Claude: You're already on the latest version (2026.4.15). Here's the situation:

The error is in openclaw's closed/bundled code — it's not something you can directly patch. The logic at line 9597 of [pi-embedded-runner-DN0VbqlW.js](vscode-webview://****** fires when the model returns a stop response with zero usable payloads, after exhausting retry attempts.

What you can try:

Likely transient — empty responses from Claude via OpenRouter happen occasionally; retrying the same prompt usually works Switch model — in [openclaw.json](vscode-webview://***** you have openrouter/auto configured as an alias; trying it as the primary model might route around flaky responses Report it — if it's happening consistently with a specific prompt/flow, file an issue with the openclaw project so they can improve the retry logic The error itself is surfaced correctly by openclaw — it's not silently failing, just telling you the agent got an empty response it couldn't recover from.

Steps to reproduce

Version: OpenClaw 2026.4.15 Provider: OpenRouter Model(s) tested:

openrouter/openai/gpt-4o-mini openrouter/mistralai/mistral-7b-instruct openrouter/anthropic/claude-3.5-sonnet

Expected behavior

Agent should reply in the same Telegram thread, as in v2026.2.10.

Actual behavior

No reply is posted in the thread; gateway logs reply target not found.

OpenClaw version

OpenClaw 2026.4.15

Operating system

macOS 15.7.5

Install method

No response

Model

sonnet-4.6, gpt-4o-mini

Provider / routing chain

openclaw -> openrouter -> gpt-4o-mini

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

extent analysis

TL;DR

The issue is likely due to a compatibility bug between OpenClaw 2026.4.15 and OpenRouter, causing empty responses, and a workaround may involve switching models or retrying prompts.

Guidance

  • Try retrying the same prompt to see if the issue is transient, as suggested by Claude.
  • Switch the model to a different one, such as using openrouter/auto as the primary model, to potentially route around flaky responses.
  • If the issue persists, report it to the OpenClaw project with specific prompt/flow details to help improve the retry logic.
  • Verify that the API key, config, credits, and model choice are correct, as confirmed by Chat's diagnosis.

Example

No code snippet is provided as the issue is related to a compatibility bug and not a code-specific problem.

Notes

The issue is specific to OpenClaw 2026.4.15 and OpenRouter, and the error is surfaced correctly by OpenClaw. The problem may not be resolved by simply updating or changing configurations.

Recommendation

Apply workaround: Switch models or retry prompts, as the issue is likely due to a compatibility bug and not a configuration or setup problem. This is because the error is specific to OpenClaw 2026.4.15 and OpenRouter, and the suggested workarounds may help mitigate the issue.

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

Agent should reply in the same Telegram thread, as in v2026.2.10.

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 - ✅(Solved) Fix [Bug]: (payloads=0) when using OpenRouter [2 pull requests, 1 comments, 2 participants]