openclaw - ✅(Solved) Fix [Bug]: Google Gemini image_generate fails with HTTP/2 stream timeout after 12000 on latest stable [1 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#68104Fetched 2026-04-18 05:53:55
View on GitHub
Comments
1
Participants
2
Timeline
3
Reactions
0
Timeline (top)
commented ×1cross-referenced ×1referenced ×1

On OpenClaw 2026.4.15 (latest stable), image_generate fails for Google Gemini image models with:

  • HTTP/2: "stream timeout after 12000"

This happens even though the request appears to succeed on the Google side, and the image is visible in Google AI Studio logs.

So the failure appears to be in OpenClaw’s local fetch/transport path after request submission, not in Gemini image generation itself.

Error Message

error [tools] image_generate failed: All image generation models failed (2): google/gemini-3-pro-image-preview: fetch failed | HTTP/2: "stream timeout after 12000" | google/gemini-3.1-flash-image-preview: fetch failed | HTTP/2: "stream timeout after 12000" error [tools] image_generate failed: All image generation models failed (2): google/gemini-3.1-flash-image-preview: terminated | HTTP/2: "stream timeout after 12000" | google/gemini-3-pro-image-preview: fetch failed | HTTP/2: "stream timeout after 12000"

Root Cause

Notes / Suspected Root Cause

Fix Action

Fix / Workaround

  • Google image generation provider uses postJsonRequest(... timeoutMs: 60000, dispatcherPolicy)
  • Shared provider HTTP code intends to use a 60s guarded timeout
  • Despite that, runtime still fails with HTTP/2: "stream timeout after 12000"

PR fix notes

PR #68114: Infra/fetch-guard: keep guarded fetch on HTTP/1 when pinDns is disabled (#68104)

Description (problem / solution / changelog)

Summary

  • Problem: Google Gemini image_generate calls intermittently fail with HTTP/2: "stream timeout after 12000" well before the provider's own 60s timeout (openclaw#68104).
  • Why it matters: Users lose long-running image generations (and any other guarded provider call that runs with pinDns: false and no custom dispatcher policy) to a transport-level abort the caller never asked for.
  • What changed: In fetchWithSsrFGuard, the "DNS pinning disabled + no caller policy" branch now returns a dedicated HTTP/1 undici agent (createHttp1Agent(), i.e. allowH2: false) instead of returning null and falling through to the ambient global dispatcher.
  • What did NOT change (scope boundary): SSRF policy (private-network allowlisting, resolvePinnedHostnameWithPolicy, explicit-proxy enforcement), redirect handling, timeout guard, audit capture, public API, and config/schema/help surfaces are all untouched.

Change Type

  • Bug fix

Scope

  • Integrations
  • Gateway / orchestration

Linked Issue/PR

  • Closes #68104
  • This PR fixes a bug or regression

Root Cause

  • Root cause: createPolicyDispatcherWithoutPinnedDns in src/infra/net/fetch-guard.ts returned null when the caller passed pinDns: false without a dispatcherPolicy. With no dispatcher attached, the request resolved through Node's built-in fetch, which uses the global undici dispatcher. Since bumping to undici 8, the default global agent negotiates HTTP/2 via ALPN, and generativelanguage.googleapis.com supports HTTP/2. The undici h2 client then applies its own stream timeout (see client-h2.js, InformationalError("HTTP/2: \"stream timeout after ${requestTimeout}\"")), which aborts long Gemini image_generate responses before the provider-level 60s timeout fires. Every other branch in this function (pinned DNS + direct, pinned DNS + env proxy, pinned DNS + explicit proxy, unpinned DNS + explicit proxy) was already pinned to HTTP/1 via HTTP1_ONLY_DISPATCHER_OPTIONS; only the unpinned-DNS + no-policy branch slipped through.
  • Missing detection / guardrail: fetch-guard.ssrf.test.ts exercised pinDns: false only with an explicit dispatcherPolicy (and the Google/OpenAI-compat provider tests mock postJsonRequest / fetch, so they never see the real dispatcher wiring). The unpinned-DNS + no-policy code path had no regression coverage.
  • Contributing context: Undici 8's default-on HTTP/2 + openclaw's existing preference to keep guarded dispatchers on HTTP/1.1 until the h2 path has been re-validated end-to-end.

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
  • Target test or file: src/infra/net/fetch-guard.ssrf.test.ts — new case forces HTTP/1 dispatcher when DNS pinning is disabled with no explicit policy.
  • Scenario the test should lock in: fetchWithSsrFGuard({ pinDns: false, /* no dispatcherPolicy */ }) must construct an undici Agent with { allowH2: false } and attach it as init.dispatcher, never falling through to the ambient global dispatcher.
  • Why this is the smallest reliable guardrail: it pins the exact constructor options of the dispatcher that the fix path creates, so any future "return null here again" regression (or mixed ambient-dispatcher regression) fails the assertion directly, without needing a live network or a contrived h2 timeout.
  • Existing test that already covers this (if any): none — the closest existing pinDns: false case always supplies an explicit proxy policy.

User-visible / Behavior Changes

  • Guarded provider HTTP requests that run with pinDns: false and no custom dispatcher policy (Google Gemini image_generate, OpenAI-compatible multipart audio, Google TTS, etc.) now consistently negotiate HTTP/1.1 the same way every other guarded path already did. Users who hit openclaw#68104 on long Gemini image_generate requests should stop seeing HTTP/2: "stream timeout after 12000" aborts before the caller's own timeout fires.
  • No config, schema, or default-value changes.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No (same URLs, same headers, same timeout, same SSRF policy; only the transport ALPN preference changed from "let the OS decide" to "HTTP/1.1").
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Runtime controls explicitly unchanged: the SSRF pipeline still calls resolvePinnedHostnameWithPolicy(parsedUrl.hostname, ...) before any dispatcher is constructed, so hostname allowlisting, private-network enforcement, and proxy-endpoint SSRF checks are all identical. The fix is a runtime transport tweak on an already-allowlisted, already-policy-checked request; it does not rely on prompt text or caller cooperation.

Repro + Verification

Environment

  • OS: macOS 25.3 (host) — same code path applies on all platforms since it is provider-agnostic.
  • Runtime: Node 22+ via pnpm test harness (vitest).
  • Model/provider: Google Gemini image_generate (reporter) — reproducible in unit test against fetchWithSsrFGuard directly.

Steps

  1. pnpm test src/infra/net/fetch-guard.ssrf.test.ts
  2. pnpm test src/infra/net (full infra/net suite)
  3. pnpm test extensions/google/image-generation-provider.test.ts extensions/google/speech-provider.test.ts src/media-understanding/openai-compatible-audio.pin-dns.test.ts extensions/minimax/music-generation-provider.test.ts (all other pinDns: false callers)

Expected

  • All existing cases green; new regression case green; no neighbouring provider test regresses.

Actual

  • src/infra/net/fetch-guard.ssrf.test.ts: 42/42 passed (was 41/41; +1 new case).
  • src/infra/net: 87/87 passed across 6 files.
  • Related provider tests: 21/21 passed across 4 files.

Evidence

  • Failing case converted to a passing regression test (see src/infra/net/fetch-guard.ssrf.test.ts — the new forces HTTP/1 dispatcher... case fails against the prior return null implementation because no dispatcher is attached and agentCtor is never called).

Human Verification

  • Verified scenarios:
    • New regression test asserts Agent is constructed with { allowH2: false } and that init.dispatcher is populated on the final fetchImpl call.
    • Existing keeps explicit proxy transport policy when DNS pinning is disabled case still passes, proving the explicit-proxy branch is untouched.
    • extensions/google/image-generation-provider.test.ts (mocks global fetch; now silently also receives an init.dispatcher but asserts use objectContaining({ body, method }), so unaffected).
  • Edge cases checked:
    • closeDispatcher is compatible with the agent returned by createHttp1Agent() (same shape used by the existing pinned and explicit-proxy branches).
    • No new lint errors reported on touched files.
    • SSRF hostname/policy checks still run before dispatcher construction (call site unchanged).
  • What I did not verify:
    • A live end-to-end Gemini image_generate round-trip (requires network + API keys); the h2 stream-timeout trigger is upstream behavior and not deterministically reproducible offline.

Compatibility / Migration

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

Risks and Mitigations

  • Risk: A provider endpoint that previously benefited from HTTP/2 multiplexing on the ambient dispatcher would no longer get it on this branch.
    • Mitigation: Every other guarded branch in the same function already uses HTTP/1-only agents, so this is a consistency fix rather than a new constraint; callers that want HTTP/2 can still opt in by providing a dispatcherPolicy and the explicit wiring for it.

Tests Run

  • pnpm test src/infra/net/fetch-guard.ssrf.test.ts — 42 passed.
  • pnpm test src/infra/net — 87 passed across 6 files.
  • pnpm test extensions/google/image-generation-provider.test.ts extensions/google/speech-provider.test.ts src/media-understanding/openai-compatible-audio.pin-dns.test.ts extensions/minimax/music-generation-provider.test.ts — 21 passed across 4 files.

Made with Cursor

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/infra/net/fetch-guard.ssrf.test.ts (modified, +33/-0)
  • src/infra/net/fetch-guard.ts (modified, +10/-2)

Code Example

{
  "agents": {
    "defaults": {
      "imageGenerationModel": {
        "primary": "google/gemini-3-pro-image-preview",
        "fallbacks": ["google/gemini-3.1-flash-image-preview"]
      },
      "mediaGenerationAutoProviderFallback": false
    }
  }
}

---

A fresh and energizing Matcha Granola Breakfast Bowl on a light marble surface with soft natural morning light. The bowl contains creamy green matcha yoghurt topped with golden granola, sliced fresh strawberries, and fresh mint leaves, drizzled with honey. The exact JOY of MATCHA dark green metal tin from the reference image is physically placed next to the bowl, clearly visible and readable. Color palette: soft pinks, mint greens, fresh whites. Style: clean modern lifestyle, food photography, top-down view, no text, no people, square format 1:1, high resolution.

---

/Users/openclaw/.openclaw/workspace/vault/10-projects/Joy-of-Matcha/packshots/ceremonial-matcha-2.jpg

---

Google Gemini image via `image_generate` timed out again:
- `google/gemini-3.1-flash-image-preview`: terminated, `HTTP/2: "stream timeout after 12000"`
- `google/gemini-3-pro-image-preview`: fetch failed, `HTTP/2: "stream timeout after 12000"`

---

error [tools] image_generate failed: All image generation models failed (2): google/gemini-3-pro-image-preview: fetch failed | HTTP/2: "stream timeout after 12000" | google/gemini-3.1-flash-image-preview: fetch failed | HTTP/2: "stream timeout after 12000"

---

error [tools] image_generate failed: All image generation models failed (2): google/gemini-3.1-flash-image-preview: terminated | HTTP/2: "stream timeout after 12000" | google/gemini-3-pro-image-preview: fetch failed | HTTP/2: "stream timeout after 12000"
RAW_BUFFERClick to expand / collapse

Summary

On OpenClaw 2026.4.15 (latest stable), image_generate fails for Google Gemini image models with:

  • HTTP/2: "stream timeout after 12000"

This happens even though the request appears to succeed on the Google side, and the image is visible in Google AI Studio logs.

So the failure appears to be in OpenClaw’s local fetch/transport path after request submission, not in Gemini image generation itself.

Environment

  • OpenClaw version: 2026.4.15
  • Channel: stable
  • OS: macOS Darwin 25.3.0 arm64
  • Node: v22.22.0
  • Install method: global package install
  • Provider: Google Gemini API
  • Image models tested:
    • google/gemini-3-pro-image-preview
    • google/gemini-3.1-flash-image-preview

Config

Relevant config:

{
  "agents": {
    "defaults": {
      "imageGenerationModel": {
        "primary": "google/gemini-3-pro-image-preview",
        "fallbacks": ["google/gemini-3.1-flash-image-preview"]
      },
      "mediaGenerationAutoProviderFallback": false
    }
  }
}

Google provider is configured and authenticated.

Steps to Reproduce

  1. Configure Google Gemini image generation as default provider
  2. Use image_generate with a prompt and reference image
  3. Example prompt:
A fresh and energizing Matcha Granola Breakfast Bowl on a light marble surface with soft natural morning light. The bowl contains creamy green matcha yoghurt topped with golden granola, sliced fresh strawberries, and fresh mint leaves, drizzled with honey. The exact JOY of MATCHA dark green metal tin from the reference image is physically placed next to the bowl, clearly visible and readable. Color palette: soft pinks, mint greens, fresh whites. Style: clean modern lifestyle, food photography, top-down view, no text, no people, square format 1:1, high resolution.
  1. Reference image path:
/Users/openclaw/.openclaw/workspace/vault/10-projects/Joy-of-Matcha/packshots/ceremonial-matcha-2.jpg

Expected Behavior

OpenClaw should return the generated image and save/deliver the media normally.

Actual Behavior

OpenClaw fails with transport timeout errors:

Google Gemini image via `image_generate` timed out again:
- `google/gemini-3.1-flash-image-preview`: terminated, `HTTP/2: "stream timeout after 12000"`
- `google/gemini-3-pro-image-preview`: fetch failed, `HTTP/2: "stream timeout after 12000"`

Gateway log lines:

error [tools] image_generate failed: All image generation models failed (2): google/gemini-3-pro-image-preview: fetch failed | HTTP/2: "stream timeout after 12000" | google/gemini-3.1-flash-image-preview: fetch failed | HTTP/2: "stream timeout after 12000"

and later:

error [tools] image_generate failed: All image generation models failed (2): google/gemini-3.1-flash-image-preview: terminated | HTTP/2: "stream timeout after 12000" | google/gemini-3-pro-image-preview: fetch failed | HTTP/2: "stream timeout after 12000"

Additional Evidence

  • Google AI Studio logs show the image request completed and the image was generated
  • So the problem does not appear to be a Gemini generation failure
  • It appears to be an OpenClaw-side HTTP/2 transport/fetch handling issue

Notes / Suspected Root Cause

I inspected the installed build and found:

  • Google image generation provider uses postJsonRequest(... timeoutMs: 60000, dispatcherPolicy)
  • Shared provider HTTP code intends to use a 60s guarded timeout
  • Despite that, runtime still fails with HTTP/2: "stream timeout after 12000"

This suggests the effective failure is below the tool/provider timeout layer, possibly in the current transport path used for these requests.

Impact

Google Gemini image generation is unusable on latest stable in this setup, even though the provider itself is working.

extent analysis

TL;DR

The issue can be resolved by adjusting the HTTP/2 stream timeout settings in OpenClaw to match the intended 60s timeout.

Guidance

  • Investigate the dispatcherPolicy used in the postJsonRequest function to ensure it aligns with the intended 60s timeout.
  • Verify the effective timeout value in the transport path by checking the HTTP client configuration or logging the actual timeout values.
  • Consider increasing the timeout value to a higher setting, such as 120s, to accommodate potential delays in the Google Gemini image generation process.
  • Review the OpenClaw documentation to see if there are any configuration options or environment variables that can be used to adjust the HTTP/2 stream timeout.

Example

No code snippet is provided as the issue seems to be related to configuration or internal OpenClaw settings rather than a specific code block.

Notes

The issue appears to be specific to the OpenClaw version 2026.4.15 and the Google Gemini image generation provider. The problem may not be present in other versions or providers.

Recommendation

Apply a workaround by adjusting the HTTP/2 stream timeout settings to a higher value, such as 120s, to accommodate potential delays in the Google Gemini image generation process. This should help mitigate the issue until a permanent fix is available.

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

openclaw - ✅(Solved) Fix [Bug]: Google Gemini image_generate fails with HTTP/2 stream timeout after 12000 on latest stable [1 pull requests, 1 comments, 2 participants]