linshenkx/prompt-optimizer · warning · Error

Failed to fetch image source: ${response.status}

Error message

Failed to fetch image source: ${response.status}

What it means

Thrown by downloadImageSource when fetching an image over HTTP(S) returns a non-ok response status. The function attempts to download the image bytes via fetch so it can trigger a blob download, and any response with response.ok === false (4xx/5xx) raises this error before the blob conversion. Note the surrounding catch swallows it and falls back to an anchor download, so it mainly surfaces when fetchImpl itself is missing or the fallback also fails.

Source

Thrown at packages/ui/src/utils/image-download.ts:179

  const urlApi = options.urlApi || URL

  if (src.match(DATA_URL_PATTERN)) {
    downloadBlob(dataUrlToBlob(src), filename, urlApi)
    return true
  }

  if (src.match(BLOB_URL_PATTERN)) {
    triggerAnchorDownload(src, filename)
    return true
  }

  if (src.match(HTTP_URL_PATTERN)) {
    const fetchImpl = options.fetchImpl || globalThis.fetch
    if (typeof fetchImpl === 'function') {
      try {
        const response = await fetchImpl(src)
        if (!response.ok) {
          throw new Error(`Failed to fetch image source: ${response.status}`)
        }
        const blob = await response.blob()
        downloadBlob(blob, filename, urlApi)
        return true
      } catch {
        triggerAnchorDownload(src, filename)
        return true
      }
    }
  }

  triggerAnchorDownload(src, filename)
  return true
}

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Verify the image URL directly (curl -I) and confirm it returns 200 without auth headers
  2. If the endpoint requires auth or custom headers, pass an options.fetchImpl that adds them
  3. Handle 403 hotlink protection by proxying the image through your own server or using a referrerPolicy-capable fetch
  4. Rely on the built-in anchor-download fallback or implement your own fallback when the blob path fails

Example fix

// before
await downloadImageSource('https://cdn.example.com/img.png', 'img.png')
// after - supply an authenticated fetch implementation
await downloadImageSource('https://cdn.example.com/img.png', 'img.png', {
  fetchImpl: (input, init) => fetch(input, {
    ...init,
    headers: { ...init?.headers, Authorization: `Bearer ${token}` },
  }),
})
Defensive patterns

Strategy: fallback

Validate before calling

const canFetchImage = async (src: string): Promise<boolean> => {
  try {
    const head = await fetch(src, { method: 'HEAD' })
    return head.ok
  } catch {
    return false
  }
}

Type guard

const isHttpUrl = (src: string): boolean => /^https?:\/\//i.test(src)

Try / catch

try {
  await downloadImageSource(src, filename)
} catch {
  // library already falls back to anchor download; add your own fallback (open in new tab, proxy) here
  window.open(src, '_blank')
}

Prevention

When it happens

Trigger: Calling downloadImageSource with a src matching an HTTP(S) URL where the server returns 403 (hotlink protection), 404, 401, or 5xx; passing a custom options.fetchImpl that returns non-ok responses; CORS-blocked responses surfaced as network errors.

Common situations: Hotlinked images protected by Referer/Origin checks returning 403; expired or signed CDN URLs returning 404/410; authenticated image endpoints requiring headers not passed through; environments without fetch causing anchor fallback.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/f7bb8aa2113b7904. Report an issue: GitHub.