Instagram: "Timeout downloading media" (Meta 2207003) doesn't say which media failed, or that Meta is the one fetching
Description
When Meta returns error code 2207003, Postiz surfaces it to the user as:
Timeout downloading media, please try again
That string is mapped at libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts:159-162. It is close to unactionable, and for self-hosters it is actively misleading. Four separate problems:
1. It doesn't say which media failed. Container creation runs inside Promise.all(firstPost.media.map(...)) (instagram.provider.ts:~659). When one item rejects, Promise.all rejects immediately and the only trace of which item is an at async Promise.all (index 4) line buried in the raw stack inside the Post.error JSON column. The index is never mapped back to a filename or URL, and it is not shown in the UI at all. On an 8-image carousel the user is told "media" failed with no way to know which one.
2. It doesn't say who timed out. The phrasing reads as though Postiz failed to read its own storage. The natural user reaction is "but all my media is in Postiz". In reality Postiz sends Meta a URL and Meta's servers fetch it from the user's public Postiz instance — so the timeout is Meta's, pulling data out of your deployment. Nothing in the message conveys that, and it sends people looking in entirely the wrong place.
3. "Please try again" is wrong for this failure mode. For large media on a constrained uplink this is deterministic, not transient. Retrying reproduces it exactly. The message advises the one thing guaranteed not to work.
4. No diagnostic context is captured. Media size, elapsed time and bytes transferred are all available at the point of failure but none are recorded, so there is nothing to correlate against and no way to tell 2207003 (slow) apart from 2207052 (unreachable) without a reverse-proxy log.
Related but distinct: #1472 and #1004 both cover "Media fetch failed" (9004 / 2207052), where Meta cannot fetch the URL at all. This is code 2207003, where Meta reaches the URL fine and the transfer is then cut short. Same user-facing dead end, different cause.
Reproduction steps
- Self-host Postiz with
STORAGE_PROVIDER=localbehind a public HTTPS reverse proxy, on a connection with a modest upload speed (mine measures ~2.5 MB/s / ~20 Mbit). - Upload 8 full-resolution phone photos via
POST /api/public/v1/upload— roughly 4–6 MB each, ~34 MB total. - Create an Instagram carousel post using all 8 and publish.
- Publishing fails.
Post.statebecomesERRORand the UI shows only "Timeout downloading media, please try again".
Expected behavior
An error a self-hoster can act on. Something like:
Instagram timed out downloading photo-04.jpg (image 4 of 8, 5.1 MB) from
https://<your-postiz>/uploads/2026/08/30/c8ee….jpg. Instagram downloads media from your Postiz instance rather than receiving an upload. Meta fetches carousel items in parallel, so a large carousel on a slow upload link can exceed their fetch timeout. Consider reducing image file sizes — Instagram renders feed images at 1080px wide.
Concretely, four changes:
- Surface the failing item's filename, carousel index and file size in the user-facing error, not just in a stack trace inside a JSON column.
- Reword so it is unambiguous that Meta is fetching from the user's instance.
- Swap
Promise.allforPromise.allSettledso every failing item is reported in one pass instead of only the first to reject. - Log bytes served and elapsed time for each media fetch, so 2207003 can be distinguished from 2207052 without reading reverse-proxy logs.
A pre-flight warning at post time when a carousel's total payload is large (or optional server-side downscaling on upload) would prevent the failure altogether, since Instagram re-compresses to 1080px regardless.
Actual Behavior with Screenshots
UI and Post.error show only:
Timeout downloading media, please try againDecoded from the Post.error column:
ApplicationFailure: Timeout downloading media, please try again
at InstagramProvider.fetch (/app/libraries/nestjs-libraries/src/integrations/social.abstract.ts:455:11)
at processTicksAndRejections (node:internal/process/task_queues:105:5)
at /app/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts:725:11
at async Promise.all (index 4)
at InstagramProvider.postPending (/app/libraries/nestjs-libraries/src/integrations/social/instagram.provider.ts:659:20)
at PostActivity.postSocialInternal (/app/apps/orchestrator/src/activities/post.activity.ts:268:11)
type: 'bad_body'index 4 is the only clue to which image failed, and it is not shown anywhere in the UI.
What was actually happening. I only found the cause by reading the reverse-proxy access log. Meta was reaching the server and getting 200s — but the byte counts served were short, and short by a different amount on each attempt:
time file bytes served actual size
31/Aug 18:12:09 e8f9cfd1… 4,733,105 / 4,733,105 complete
31/Aug 18:12:10 36a6d571… 4,685,357 / 4,866,133 CUT
31/Aug 18:12:10 c8eeee6c… 4,750,893 / 5,398,334 CUT
31/Aug 18:12:10 eecc1e30… 4,521,517 / 6,270,719 CUT
31/Aug 18:12:10 3859dfe1… 3,489,325 / 5,542,203 CUT
01/Sep 00:53:26 eecc1e30… 3,276,333 / 6,270,719 CUT (different offset)Note the timestamps: facebookexternalhit requests four items within the same second. Meta fetches carousel media in parallel, so on a ~2.5 MB/s uplink each concurrent stream gets roughly 600 KB/s and a 6 MB image needs ~10s on its own — past Meta's fetch timeout. Files under ~2.5 MB completed every time; files over ~4.5 MB were cut every time, at varying offsets. That varying offset is what identifies it as a timeout rather than a size limit.
Resizing the images to 1440px long edge (56.4 MB → 5.9 MB across the library) fixed it completely. No Postiz configuration was wrong at any point — but nothing in the error pointed anywhere near the actual problem.
Operating system
Linux (Debian, Docker Compose, STORAGE_PROVIDER=local, nginx reverse proxy)
Node Version
Bundled container image
Provide any additional context for the Bug.
- Postiz
v2.23.0(NEXT_PUBLIC_VERSION), self-hosted via Docker Compose STORAGE_PROVIDER=local,UPLOAD_DIRECTORY=/uploads- Public HTTPS via nginx reverse proxy, valid certificate; media URLs verified publicly reachable and returning
200 image/jpegfrom outside the network - Facebook/Instagram fetch user-agent observed in proxy logs as
facebookexternalhit/1.1from69.171.234.xand173.252.x.x - Error code reference: Meta
2207003— mapped ininstagram.provider.ts:159
Source: gitroomhq/postiz-app