Skip to content

fix: add AbortController timeout to fetchImageEndpoint - #3105

Merged
diegosouzapw merged 2 commits into
cheaper-inference:release/v3.8.9from
mgarmash:fix/image-generation-fetch-timeout
Jun 3, 2026
Merged

diegosouzapw merged 2 commits into
cheaper-inference:release/v3.8.9from
mgarmash:fix/image-generation-fetch-timeout

Conversation

@mgarmash

@mgarmash mgarmash commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Problem

fetchImageEndpoint() in open-sse/handlers/imageGeneration.ts uses raw fetch() without any timeout control. When calling upstream image generation APIs (OpenAI, Nebius, etc.) that take 20-30+ seconds, Next.js self-hosted default timeout kills the connection, producing:

{"error":{"message":"terminated","type":"upstream_error","code":"upstream_error"}}

The chat/SSE endpoint already uses fetchWithTimeout() with FETCH_TIMEOUT_MS (default 600s) via open-sse/config/constants.ts, but image generation does not.

Fix

  • Import fetchWithTimeout and getConfiguredTimeout from @/shared/utils/fetchTimeout (the same utility already used in the SSE code path)
  • Replace raw fetch() with fetchWithTimeout() in fetchImageEndpoint(), using timeoutMs: getConfiguredTimeout()

Default timeout: 120s (OMNIROUTE_DEFAULT_FETCH_TIMEOUT_MS env var) or FETCH_TIMEOUT_MS env var.

Files changed

  • open-sse/handlers/imageGeneration.ts — add import, replace fetch with fetchWithTimeout in fetchImageEndpoint

Testing

Reproduced issue with /v1/images/generations requests taking >30s. After fix, requests complete successfully within the configured timeout window.

fetchImageEndpoint uses raw fetch() without timeout control.
Long-running image generation requests (~20-30s) are killed
by Next.js default timeout, producing upstream_error responses.

Replace fetch() with fetchWithTimeout() from shared utils,
defaulting to FETCH_TIMEOUT_MS (120s via OMNIROUTE_DEFAULT_FETCH_TIMEOUT_MS).
@mgarmash
mgarmash requested a review from diegosouzapw as a code owner June 3, 2026 12:51

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates fetchWithTimeout and getConfiguredTimeout into the fetchImageEndpoint function within open-sse/handlers/imageGeneration.ts to enforce request timeouts. The review feedback recommends adding unit tests for this new behavior to comply with the repository style guide, and catching FetchTimeoutError or AbortError to return a 504 Gateway Timeout status code instead of a misleading 502 error.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread open-sse/handlers/imageGeneration.ts Outdated
extractComfyOutputFiles,
} from "../utils/comfyuiClient.ts";
import { fetchRemoteImage } from "@/shared/network/remoteImageFetch";
import { fetchWithTimeout, getConfiguredTimeout } from "@/shared/utils/fetchTimeout";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to Rule 9 of the Repository Style Guide, we must always include tests when changing production code in open-sse/. Please add unit tests to verify the new timeout behavior of fetchImageEndpoint and ensure that fetchWithTimeout is correctly invoked with the configured timeout.

Suggested change
import { fetchWithTimeout, getConfiguredTimeout } from "@/shared/utils/fetchTimeout";
import { fetchWithTimeout, getConfiguredTimeout, FetchTimeoutError } from "@/shared/utils/fetchTimeout";
References
  1. Always include tests when changing production code (src/, open-sse/, electron/, bin/). (link)

Comment thread open-sse/handlers/imageGeneration.ts Outdated
Comment on lines 2418 to 2423
const response = await fetchWithTimeout(url, {
method: "POST",
headers,
body,
timeoutMs: getConfiguredTimeout(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When an upstream image generation request times out, returning a 502 (Bad Gateway) status code is misleading. To align with other timeout handlers in this file (which return 504), we should catch FetchTimeoutError or AbortError and return a 504 (Gateway Timeout) status code.

    let response;
    try {
      response = await fetchWithTimeout(url, {
        method: "POST",
        headers,
        body,
        timeoutMs: getConfiguredTimeout(),
      });
    } catch (err: any) {
      if (err instanceof FetchTimeoutError || err?.name === "AbortError") {
        if (log) {
          log.error("IMAGE", `${provider} fetch error: ${err.message}`);
        }
        return {
          success: false,
          status: 504,
          error: `Image provider error: ${sanitizeErrorMessage(err.message || err)}`,
        };
      }
      throw err;
    }

@kilo-code-bot

kilo-code-bot Bot commented Jun 3, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • open-sse/handlers/imageGeneration.ts

Reviewed by nemotron-3-super-120b-a12b-20230311:free · 372,991 tokens

Address review feedback from gemini-code-assist:
- Import FetchTimeoutError and catch it in fetchImageEndpoint
- Return 504 (Gateway Timeout) instead of 502 for timeout/AbortError
- Add 3 focused unit tests for timeout, non-timeout, and success paths

Clarifies timeout semantics: timeout is a gateway timeout (504), not
a bad gateway (502). Non-timeout fetch errors remain 502.
@diegosouzapw
diegosouzapw changed the base branch from main to release/v3.8.9 June 3, 2026 21:00
@diegosouzapw

Copy link
Copy Markdown
Collaborator

Thanks, @mgarmash! 🙏 Wrapping fetchImageEndpoint in fetchWithTimeout is the right call — image-gen was the one upstream path with no AbortController bound, so a stuck provider could hang until Next's server timeout. Verified the timer is cleared on both success and error, the error is sanitized (no stack leak), and a timeout correctly surfaces as a 504. The FETCH_TIMEOUT_MS env var governs the bound for operators running slower backends (ComfyUI/video). Merging into release/v3.8.9 for the next release.

@diegosouzapw
diegosouzapw merged commit 0331e81 into cheaper-inference:release/v3.8.9 Jun 3, 2026
2 checks passed
@diegosouzapw diegosouzapw mentioned this pull request Jun 3, 2026
diegosouzapw added a commit that referenced this pull request Jun 3, 2026
…ors hall

Adds entries for #3097, #3101 (deepseek-web #2942/#2820), #3104, #3105, #3107,
#3109, #3111, #3113, #3115, #3122, #3125, #3127, #3129, plus a Contributors
section crediting all v3.8.9 contributors. Stamps the 3.8.9 release date.
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…ence#3105)

* fix: add AbortController timeout to fetchImageEndpoint

fetchImageEndpoint uses raw fetch() without timeout control.
Long-running image generation requests (~20-30s) are killed
by Next.js default timeout, producing upstream_error responses.

Replace fetch() with fetchWithTimeout() from shared utils,
defaulting to FETCH_TIMEOUT_MS (120s via OMNIROUTE_DEFAULT_FETCH_TIMEOUT_MS).

* fix: return 504 for image fetch timeout, add tests

Address review feedback from gemini-code-assist:
- Import FetchTimeoutError and catch it in fetchImageEndpoint
- Return 504 (Gateway Timeout) instead of 502 for timeout/AbortError
- Add 3 focused unit tests for timeout, non-timeout, and success paths

Clarifies timeout semantics: timeout is a gateway timeout (504), not
a bad gateway (502). Non-timeout fetch errors remain 502.

---------

Co-authored-by: mgarmash <mgarmash@37bytes.com>
Poid-ZA pushed a commit to Poid-ZA/OmniRoute that referenced this pull request Aug 5, 2026
…ence#3105)

* fix: add AbortController timeout to fetchImageEndpoint

fetchImageEndpoint uses raw fetch() without timeout control.
Long-running image generation requests (~20-30s) are killed
by Next.js default timeout, producing upstream_error responses.

Replace fetch() with fetchWithTimeout() from shared utils,
defaulting to FETCH_TIMEOUT_MS (120s via OMNIROUTE_DEFAULT_FETCH_TIMEOUT_MS).

* fix: return 504 for image fetch timeout, add tests

Address review feedback from gemini-code-assist:
- Import FetchTimeoutError and catch it in fetchImageEndpoint
- Return 504 (Gateway Timeout) instead of 502 for timeout/AbortError
- Add 3 focused unit tests for timeout, non-timeout, and success paths

Clarifies timeout semantics: timeout is a gateway timeout (504), not
a bad gateway (502). Non-timeout fetch errors remain 502.

---------

Co-authored-by: mgarmash <mgarmash@37bytes.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…ence#3105)

* fix: add AbortController timeout to fetchImageEndpoint

fetchImageEndpoint uses raw fetch() without timeout control.
Long-running image generation requests (~20-30s) are killed
by Next.js default timeout, producing upstream_error responses.

Replace fetch() with fetchWithTimeout() from shared utils,
defaulting to FETCH_TIMEOUT_MS (120s via OMNIROUTE_DEFAULT_FETCH_TIMEOUT_MS).

* fix: return 504 for image fetch timeout, add tests

Address review feedback from gemini-code-assist:
- Import FetchTimeoutError and catch it in fetchImageEndpoint
- Return 504 (Gateway Timeout) instead of 502 for timeout/AbortError
- Add 3 focused unit tests for timeout, non-timeout, and success paths

Clarifies timeout semantics: timeout is a gateway timeout (504), not
a bad gateway (502). Non-timeout fetch errors remain 502.

---------

Co-authored-by: mgarmash <mgarmash@37bytes.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants