Avatar photo image_not_fetchable: 404, timeouts and the 15 s limit
Sume gives an avatar photo host 15 seconds for fetch and body read. A non-2xx status or a timeout returns 400 image_not_fetchable. How to fix it.
400 image_not_fetchable on an avatar photo means Sume's preflight could not get a usable response from your URL. Two things cause it most: your host answered with a status outside 200-299 (a 403, 404 or 500, reported in details.status), or nothing useful arrived within 15 seconds (then details.status is null). The preflight runs before a job exists, so a failure creates no avatar job and no usage reservation.
The error also carries details.url_host and details.suggested_input: public_image_url. The query string is never echoed. The behaviour is described on Create new avatar, and the generic code is in the error reference, both read 2026-10-05.
One clock for the whole preflight
In the source, one AbortController is armed for 15 seconds and its signal is passed to the fetch. The timer is cleared only after the response has been checked and the body has been read for dimensions. So the 15 seconds is a single budget for connecting, waiting for headers, following redirects and downloading the file, not a per-step limit.
| What happened | details.status | details.reason | Typical cause |
|---|---|---|---|
| Host answered 404 | 404 | none | Wrong path or deleted file |
| Host answered 403 | 403 | none | Hotlink protection or an expired signed link |
| Host answered 500 | 500 | none | Origin error on your side |
| No answer inside 15 seconds, or network error | null | none | Slow origin, firewall, DNS failure |
| Redirect chain too long or unsafe | none | too_many_redirects or unsafe_url | See the redirect rules |
Reproduce it with curl
Reproduce the exact fetch before you retry the API. The command below prints the status, the content type, the time taken, and the byte size, and it aborts at 15 seconds the way Sume does.
curl -sS -L --max-time 15 -o /dev/null \
-H 'Accept: image/png,image/jpeg,image/webp,image/gif' \
-w 'status=%{http_code} type=%{content_type} secs=%{time_total} bytes=%{size_download}\n' \
'https://assets.example.com/headshot.jpg'
# status must be 2xx; secs must stay well under 15The two causes that look like Sume's fault
A 403 is the surprise that bites teams most. Storage links with an expiry time are valid when you create them and invalid by the time a queue picks the work up, and some hosts return 403 to any client that lacks a browser-like referrer. Sume sends a plain GET with an image Accept header and nothing else, so a link that works only inside your app will fail here.
A timeout is the other common one. Photos stored in a cold region, behind a slow image resizer, or on a host that renders the image on first request can take longer than 15 seconds the first time and a second the next. Warm the URL once with the curl line above, then send it to Sume.
- Expired signed links return 403 or 404 after the expiry time.
- Hosts that block unknown clients return 403 to a plain GET.
- A cold or resizing host can pass your test and miss the 15 second budget.
- A response body that arrives slowly counts against the same clock as the headers.
Retry rules
Because a failed preflight costs nothing, retrying is safe. Use a short backoff and cap the attempts, and change something between attempts: warm the URL, extend the signed link lifetime, or move the file to a faster host. A retry that sends the same cold URL will get the same answer.
If the status is a 2xx and you still see image_not_fetchable, look at details.reason. A value of unsafe_url, too_many_redirects, redirect_without_location or invalid_url points to the URL or redirect rules, covered in the redirect post and the URL post.
What a good host looks like
Host the photo where a stranger's client can read it fast: a public object store or CDN with a stable path, a long-lived link, and an image content type. Then the other checks, such as content type and pixel rules, are the only ones left to pass.
Sources
Related posts
More in Developers
- Avatar photo 400 invalid_image: under 64 px or a 6:1 aspect ratio
Sume rejects an avatar photo that is not decodable, is under 64 px on a side, or is more than 6:1. The 400 invalid_image error reports width, height and reason.
- Avatar submit response: what next_action tells your client to do
next_action has three values on avatar submits: poll_status while queued or processing, fetch_result once completed, inspect_events for failed or canceled jobs.
- Avatar sync wait: timed_out vs capacity_exhausted, and what to do
A sync avatar submit can return 2xx with sync.timed_out or sync.capacity_exhausted true. Both mean keep the job: poll status_url, never submit a new paid job.
- Avatar script too long? The 4 to 60 second window and how to split it
Sume accepts an avatar talking video only when the script estimates 4 to 60 seconds. Split longer scripts into scenes or jobs; costs from $0.74 to $33.
Written by Sume