NousResearch/hermes-agent · error

Could not fetch image: ${response.status}

Error message

Could not fetch image: ${response.status}

What it means

Thrown by startBrowserDownload() in apps/desktop/src/hooks/use-image-download.ts:28 — the fallback path of useImageDownload — when `fetch(src)` resolves with a non-OK HTTP status. The desktop first tries the IPC handler `hermes:saveImageFromUrl`; when that's missing (older shell / web preview) it fetches the image URL in the renderer and triggers a browser-style download, so any 4xx/5xx from the image host surfaces as this error.

Source

Thrown at apps/desktop/src/hooks/use-image-download.ts:28

  try {
    return new URL(src, window.location.href).pathname.split('/').filter(Boolean).pop() || 'image'
  } catch {
    return src.split(/[\\/]/).filter(Boolean).pop() || 'image'
  }
}

function isMissingIpcHandler(error: unknown): boolean {
  const message = error instanceof Error ? error.message : typeof error === 'string' ? error : ''

  return message.includes("No handler registered for 'hermes:saveImageFromUrl'")
}

async function startBrowserDownload(src: string) {
  const response = await fetch(src)

  if (!response.ok) {
    throw new Error(`Could not fetch image: ${response.status}`)
  }

  const blobUrl = URL.createObjectURL(await response.blob())
  const link = document.createElement('a')
  link.href = blobUrl
  link.download = imageFilename(src)
  link.rel = 'noopener noreferrer'
  document.body.appendChild(link)
  link.click()
  link.remove()
  window.setTimeout(() => URL.revokeObjectURL(blobUrl), 30_000)
}

/** Save an image to disk via the desktop IPC bridge, falling back to a browser
 *  download when the handler is unavailable (older shell / web preview). */
export function useImageDownload(src?: string) {
  const { t } = useI18n()
  const copy = t.desktop

View on GitHub (pinned to c896c09c42)

Solutions

  1. Verify the image URL still loads (open it directly, re-check for expired signatures) and retry the download after re-fetching a fresh URL.
  2. For auth-protected images, prefer the desktop IPC path (update the desktop shell so saveImageFromUrl exists and fetches via the main process with proper auth).
  3. If the source is a data: URL or local path, ensure it is converted to a fetchable/exportable form before download.
  4. Handle the error with the hook's notifyError path and offer re-generation of the image.

Example fix

// before
const response = await fetch(src)
if (!response.ok) throw new Error(`Could not fetch image: ${response.status}`)

// after — refresh a stale signed URL once, then retry
let url = src
let response = await fetch(url)
if (response.status === 403 || response.status === 404) {
  url = await refreshImageUrl(src)
  response = await fetch(url)
}
if (!response.ok) throw new Error(`Could not fetch image: ${response.status}`)
Defensive patterns

Strategy: retry

Validate before calling

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

Try / catch

try {
  await startBrowserDownload(src)
} catch (e) {
  if (e instanceof Error && /^Could not fetch image: (401|403|404)$/.test(e.message)) {
    const fresh = await refreshImageUrl(src) // re-sign / re-host
    if (fresh) await startBrowserDownload(fresh)
    else notifyError(e)
  } else throw e
}

Prevention

When it happens

Trigger: Image src returning 404 (expired signed URL, deleted file, typo); 401/403 for authenticated/CDN URLs requiring headers the renderer fetch cannot attach; 500 from the origin server; CORS-configured host returning an error status (fetch succeeds but response.ok false).

Common situations: An image-generation result URL that expired before the user clicked save; a gateway-hosted image on a remote backend whose auth token isn't propagated to the raw fetch; offline/proxy failures; the message referencing a local file path that the HTTP host doesn't serve.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/aade7d909a59d3c5. Report an issue: GitHub.