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
- Verify the image URL directly (curl -I) and confirm it returns 200 without auth headers
- If the endpoint requires auth or custom headers, pass an options.fetchImpl that adds them
- Handle 403 hotlink protection by proxying the image through your own server or using a referrerPolicy-capable fetch
- 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
- Pre-download check with HEAD request for user-supplied URLs
- Pass an authenticated fetchImpl for private image endpoints
- Provide server-side proxy for hotlink-protected images
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
- Network error: ${error.message}
- Example image request failed: ${resp.status}
- Anthropic API error (${error.status}): ${error.message}
- Cloudflare model search failed: ${await this.getErrorMessage
- Cross-origin connection failed: ${error.message}
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/f7bb8aa2113b7904.
Report an issue: GitHub.