openclaw - 💡(How to fix) Fix createGoogleThinkingPayloadWrapper: strip store/service_tier/metadata only for google-generative-ai (collides with Codex subscription path) [1 participants]

Official PRs (…)
ON THIS PAGE

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#61376Fetched 2026-04-08 02:59:18
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

In createGoogleThinkingPayloadWrapper (provider-stream), Google OpenAI-compat requests are dispatched with top-level store, service_tier, and metadata fields still attached. Google's OpenAI-compatible endpoint rejects these as unknown fields with HTTP 400. The wrapper already has a model.api === "google-generative-ai" guard for sanitizeGoogleThinkingPayload but does not strip the unsupported OpenAI-only top-level fields.

Downstream operators who patch this locally tend to strip those fields unconditionally in the wrapper, which then breaks the OpenAI Codex subscription path (openai-codex-responses api), because Codex requires store: false in its request body and returns HTTP 400 {"detail":"Store must be set to false"} when the field is missing.

The correct fix is to strip store / service_tier / metadata only when model.api === "google-generative-ai", co-located with the existing sanitizeGoogleThinkingPayload guard.

Root Cause

Downstream operators who patch this locally tend to strip those fields unconditionally in the wrapper, which then breaks the OpenAI Codex subscription path (openai-codex-responses api), because Codex requires store: false in its request body and returns HTTP 400 {"detail":"Store must be set to false"} when the field is missing.

Fix Action

Fix / Workaround

In createGoogleThinkingPayloadWrapper (provider-stream), Google OpenAI-compat requests are dispatched with top-level store, service_tier, and metadata fields still attached. Google's OpenAI-compatible endpoint rejects these as unknown fields with HTTP 400. The wrapper already has a model.api === "google-generative-ai" guard for sanitizeGoogleThinkingPayload but does not strip the unsupported OpenAI-only top-level fields.

Downstream operators who patch this locally tend to strip those fields unconditionally in the wrapper, which then breaks the OpenAI Codex subscription path (openai-codex-responses api), because Codex requires store: false in its request body and returns HTTP 400 {"detail":"Store must be set to false"} when the field is missing.

function createGoogleThinkingPayloadWrapper(baseStreamFn, thinkingLevel) {
  const underlying = baseStreamFn ?? streamSimple;
  return (model, context, options) => {
    return streamWithPayloadPatch(underlying, model, context, options, (payload) => {
      if (model.api === "google-generative-ai") sanitizeGoogleThinkingPayload({
        payload,
        modelId: model.id,
        thinkingLevel
      });
    });
  };
}

Code Example

function createGoogleThinkingPayloadWrapper(baseStreamFn, thinkingLevel) {
  const underlying = baseStreamFn ?? streamSimple;
  return (model, context, options) => {
    return streamWithPayloadPatch(underlying, model, context, options, (payload) => {
      if (model.api === "google-generative-ai") sanitizeGoogleThinkingPayload({
        payload,
        modelId: model.id,
        thinkingLevel
      });
    });
  };
}

---

HTTP 400
{"detail":"Store must be set to false"}

---

function createGoogleThinkingPayloadWrapper(baseStreamFn, thinkingLevel) {
  const underlying = baseStreamFn ?? streamSimple;
  return (model, context, options) => {
    return streamWithPayloadPatch(underlying, model, context, options, (payload) => {
      if (model.api === "google-generative-ai") {
        sanitizeGoogleThinkingPayload({
          payload,
          modelId: model.id,
          thinkingLevel
        });
        if (payload && typeof payload === "object") {
          delete payload.store;
          delete payload.service_tier;
          delete payload.metadata;
        }
      }
    });
  };
}
RAW_BUFFERClick to expand / collapse

Summary

In createGoogleThinkingPayloadWrapper (provider-stream), Google OpenAI-compat requests are dispatched with top-level store, service_tier, and metadata fields still attached. Google's OpenAI-compatible endpoint rejects these as unknown fields with HTTP 400. The wrapper already has a model.api === "google-generative-ai" guard for sanitizeGoogleThinkingPayload but does not strip the unsupported OpenAI-only top-level fields.

Downstream operators who patch this locally tend to strip those fields unconditionally in the wrapper, which then breaks the OpenAI Codex subscription path (openai-codex-responses api), because Codex requires store: false in its request body and returns HTTP 400 {"detail":"Store must be set to false"} when the field is missing.

The correct fix is to strip store / service_tier / metadata only when model.api === "google-generative-ai", co-located with the existing sanitizeGoogleThinkingPayload guard.

Environment

  • OpenClaw: 2026.3.28
  • Affected file (installed): /usr/lib/node_modules/openclaw/dist/provider-stream-*.js
  • Affected function: createGoogleThinkingPayloadWrapper
  • Affected provider api: google-generative-ai (Google OpenAI-compat endpoint: https://generativelanguage.googleapis.com/v1beta/openai/)
  • Colliding provider api: openai-codex-responses (Codex subscription path, https://chatgpt.com/backend-api)

Current Upstream Code (2026.3.28)

function createGoogleThinkingPayloadWrapper(baseStreamFn, thinkingLevel) {
  const underlying = baseStreamFn ?? streamSimple;
  return (model, context, options) => {
    return streamWithPayloadPatch(underlying, model, context, options, (payload) => {
      if (model.api === "google-generative-ai") sanitizeGoogleThinkingPayload({
        payload,
        modelId: model.id,
        thinkingLevel
      });
    });
  };
}

Buggy Behavior

When a model with api: "google-generative-ai" is routed through this wrapper, the payload still contains OpenAI-compat-only top-level fields:

  • store (boolean)
  • service_tier (string)
  • metadata (object)

Google's OpenAI-compat endpoint rejects requests containing any of these with HTTP 400 INVALID_ARGUMENT / unknown field. This is the same failure class reported in #53658 (fallback/replay path).

Expected Behavior

For model.api === "google-generative-ai", the wrapper should scrub the OpenAI-only top-level fields before dispatch, the same place it already runs sanitizeGoogleThinkingPayload.

Why This Matters Beyond Gemini — Codex Collision

Naive downstream fixes strip these fields unconditionally inside the wrapper. That regresses the Codex subscription path because OpenAI Codex's openai-codex-responses api requires store: false in every request body. When the field is stripped:

HTTP 400
{"detail":"Store must be set to false"}

This means the fix must be narrow — Google-api-only — or it will take out Codex agents on the same gateway.

Smallest Correct Fix

function createGoogleThinkingPayloadWrapper(baseStreamFn, thinkingLevel) {
  const underlying = baseStreamFn ?? streamSimple;
  return (model, context, options) => {
    return streamWithPayloadPatch(underlying, model, context, options, (payload) => {
      if (model.api === "google-generative-ai") {
        sanitizeGoogleThinkingPayload({
          payload,
          modelId: model.id,
          thinkingLevel
        });
        if (payload && typeof payload === "object") {
          delete payload.store;
          delete payload.service_tier;
          delete payload.metadata;
        }
      }
    });
  };
}

Key constraint: the delete block must be inside the model.api === "google-generative-ai" guard. Do not strip these fields for any other provider api.

Suggested Regression Tests

  • createGoogleThinkingPayloadWrapper with model.api === "google-generative-ai": asserts store/service_tier/metadata are stripped.
  • Same wrapper with model.api === "openai-codex-responses" and store: false on the payload: asserts store: false is preserved.
  • Same wrapper with model.api === "openai" and service_tier set: asserts it is preserved.

Related

  • #53658 — reports the Google OpenAI-compat store unknown-field 400 from the fallback/replay path (same root field-compat issue, different code site).

Notes

Local operator workaround (retired on fix): a dist-level patch on provider-stream-*.js adds the Google-guarded delete block above. Tracked locally as OC016 with the removal trigger "upstream ships conditional guard natively."

extent analysis

TL;DR

To fix the issue, update the createGoogleThinkingPayloadWrapper function to conditionally strip the store, service_tier, and metadata fields from the payload only when the model.api is "google-generative-ai".

Guidance

  • Identify the createGoogleThinkingPayloadWrapper function in the affected file (/usr/lib/node_modules/openclaw/dist/provider-stream-*.js) and update it to include the conditional field stripping.
  • Ensure the delete block is inside the model.api === "google-generative-ai" guard to avoid breaking the OpenAI Codex subscription path.
  • Verify the fix by running the suggested regression tests, including testing with model.api === "google-generative-ai" and model.api === "openai-codex-responses".

Example

The corrected createGoogleThinkingPayloadWrapper function should look like this:

function createGoogleThinkingPayloadWrapper(baseStreamFn, thinkingLevel) {
  const underlying = baseStreamFn ?? streamSimple;
  return (model, context, options) => {
    return streamWithPayloadPatch(underlying, model, context, options, (payload) => {
      if (model.api === "google-generative-ai") {
        sanitizeGoogleThinkingPayload({
          payload,
          modelId: model.id,
          thinkingLevel
        });
        if (payload && typeof payload === "object") {
          delete payload.store;
          delete payload.service_tier;
          delete payload.metadata;
        }
      }
    });
  };
}

Notes

The fix must be narrow and only strip the fields for the Google API to avoid breaking the OpenAI Codex subscription path.

Recommendation

Apply the workaround by updating the createGoogleThinkingPayloadWrapper function with the conditional field stripping, as this will fix the issue without breaking other APIs.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING