Debugging 400: image_url_fetch_failed

Fix BackgroundErase image_url_fetch_failed errors by making sure your image URL is directly accessible, returns HTTP 200, and points to the actual image file rather than a login or preview page.

Eric
Written by Eric
Updated in March 2026

A 400 image_url_fetch_failed error means BackgroundErase tried to download the file from the URL you provided, but the fetch did not succeed. This happens when the API attempts to load image_url and the remote server does not return a successful HTTP 200 response.

In plain terms, the API could not actually retrieve the image from that URL. The most common causes are expired signed links, private storage URLs, missing permissions, bad paths, blocked hotlinking, or links that work in your browser only because you are logged in.

Fastest fix: test the exact image URL outside your app, confirm it returns HTTP 200 and the actual image bytes, then retry the request. If the URL is private or fragile, switch to image_file upload instead.


What this error looks like

A typical response looks like this:

{
  "error": {
    "code": "image_url_fetch_failed",
    "message": "cannot download image_url (HTTP 403)",
    "status": 400,
    "request_id": "..."
  }
}

The important part is the HTTP status inside the message. That tells you what the remote server returned when BackgroundErase tried to fetch the URL.

  • HTTP 403 usually means forbidden or private access
  • HTTP 404 usually means the file path is wrong or the object no longer exists
  • HTTP 401 usually means the origin requires authentication
  • HTTP 500-series usually means the remote origin itself failed

How image_url works in this API

The image_url field is supported for both JSON and multipart requests. The API downloads the remote file server-side before normal image validation and processing continue.

That means the URL has to work from the server’s point of view, not just from your browser session. If the link only works because your browser already has cookies, a login session, or local network access, BackgroundErase will not be able to fetch it.

The API also accepts imageUrl as an alternate field name in JSON and multipart flows, but the underlying requirement is the same: it has to be a reachable image URL.

Quick checklist

Before changing your app code, walk through this list:

  1. Open the exact image URL in a private browser window
  2. Make sure it loads the actual image file, not an HTML page
  3. Confirm the URL returns HTTP 200
  4. Make sure the file is publicly reachable without cookies or login
  5. If using a signed URL, confirm it has not expired
  6. Retry first with a known-good public image URL
  7. If needed, switch from image_url to direct file upload

Start with a direct known-good request

The easiest way to isolate the problem is to call the API directly with a URL you know should work. This removes your app, worker, automation builder, and proxy layers from the equation.

JSON example:

curl -H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
https://api.backgrounderase.com/v2 \
-d '{
  "image_url": "https://example.com/path/to/image.jpg",
  "format": "png",
  "size": "full"
}'

Multipart example:

curl -H 'x-api-key: YOUR_API_KEY' \
-f https://api.backgrounderase.com/v2 \
-F 'image_url=https://example.com/path/to/image.jpg' \
-F 'format=png' \
-o output.png

A valid JSON request can look like this:

{
  "image_url": "https://example.com/path/to/image.jpg",
  "format": "png",
  "size": "full",
  "crop": false,
  "despill": false
}

The alternate field name imageUrl also works:

{
  "imageUrl": "https://example.com/path/to/image.jpg",
  "format": "png"
}

The most common reasons this fails

In production workflows, these are the most common causes of image_url_fetch_failed:

  • The image URL returns 403 because the object is private
  • The URL returns 404 because the path is wrong or stale
  • The link expired, especially with signed cloud-storage URLs
  • The origin requires cookies, auth headers, or a login
  • The URL points to a preview page instead of the raw image file
  • The origin blocks hotlinking or external fetches
  • The file moved after your app stored the original URL
  • A redirect chain ends at a page the API cannot use

Browser success does not always mean server success

One of the most common debugging mistakes is testing the URL in a browser tab and assuming that means the API can fetch it too. Browsers often have cookies, active sessions, and access to internal network contexts that a server-side fetch does not have.

So the real question is not “does it open for me?” The real question is “does this exact URL return a direct HTTP 200 image response without any browser state?”

Good test: open the link in a private browsing window, or fetch it from a script without any saved session or cookies.

Check the URL response directly

Before you debug your app, inspect the remote URL itself. First check the headers:

curl -I "https://example.com/path/to/image.jpg"

Then inspect it more fully in Python:

import requests

url = "https://example.com/path/to/image.jpg"
response = requests.get(url, timeout=15, allow_redirects=True)

print("Status:", response.status_code)
print("Content-Type:", response.headers.get("Content-Type"))
print("Final URL:", response.url)
print("Bytes:", len(response.content))

Or in Node.js:

const response = await fetch("https://example.com/path/to/image.jpg", {
  redirect: "follow"
});

console.log("Status:", response.status);
console.log("Content-Type:", response.headers.get("content-type"));
console.log("Final URL:", response.url);

Watch out for preview pages and redirects

A very common failure mode is using a URL that looks like an image link in the browser but is actually a preview page, file-sharing page, or HTML wrapper. In those cases the browser may render something that looks correct, but the API is not fetching the raw image object the way you expect.

Redirects can cause similar confusion. A shared link may redirect through a preview system, an expiring download endpoint, or a login page. If the final server response is not what the API can use, the request will fail.

Best practice: use direct object URLs or stable signed URLs that point straight to the image bytes rather than human-facing share pages.

Signed URLs are a frequent cause

If your product stores images in S3, GCS, Cloudflare R2, or another object store, signed URLs are often the right tool. But they can also produce image_url_fetch_failed if they expire before BackgroundErase fetches them or if the signature was generated incorrectly.

When this happens, the fastest test is to generate a fresh signed URL and call the API immediately. If that works, the problem is probably URL lifetime or signing logic rather than BackgroundErase itself.

When to switch to direct upload instead

If your image URLs are private, short-lived, user-session dependent, or hard to keep stable, direct file upload is often the better integration pattern. Using image_file avoids remote fetch problems entirely because the image bytes are sent straight to the API with the request.

This is especially helpful in server-side pipelines, worker jobs, and SaaS backends where you already have the image file in hand after upload.


image_url_fetch_failed vs body is not a valid image

These two issues are related but different. If the remote server returns a non-200 status, you will usually see image_url_fetch_failed. But if the remote URL returns HTTP 200 and the body is not actually an image, the API may get past the fetch step and then fail later when it tries to decode the body as an image.

That is why checking both status code and content type matters. A URL that returns 200 with HTML is still not a valid image source.

Final resolution path

If you are seeing image_url_fetch_failed, the cleanest path is:

  • Test the exact URL outside your app
  • Confirm it returns HTTP 200
  • Confirm it points to the actual image file
  • Make sure it does not require login or cookies
  • Regenerate the link if it is signed or expiring
  • Retry with a minimal direct API request
  • Use image_file upload if the URL path is too fragile

In most cases, the fix is not in the BackgroundErase options. It is in the accessibility and stability of the remote image URL itself.