gitroomhq/postiz-app · error · Error
Failed to fetch media: ${fileResponse.statusText}
Error message
Failed to fetch media: ${fileResponse.statusText} What it means
MastodonProvider.uploadFile fetches the media bytes from storage before uploading to Mastodon; this error means that intermediate download returned a non-ok response or empty body. The message carries the HTTP statusText of the failed fetch.
Source
Thrown at libraries/nestjs-libraries/src/integrations/social/mastodon.provider.ts:188
instanceUrl: string,
fileUrl: string,
accessToken: string,
alt?: string
) {
// The file is streamed straight from storage into the Mastodon upload
// request instead of being buffered in memory. Both requests keep the
// SSRF-safe dispatcher because the URLs are not fully under our control,
// and the whole request is rebuilt per attempt by runStreamedUpload since
// a consumed stream can't be replayed.
const media = await this.runStreamedUpload<{ id: string }>(async () => {
const fileResponse = await fetch(fileUrl, {
// identity encoding so content-length matches the streamed bytes
headers: { 'accept-encoding': 'identity' },
// @ts-ignore - undici-only option; blocks SSRF to internal IPs
dispatcher: getSsrfSafeDispatcher(),
});
if (!fileResponse.ok || !fileResponse.body) {
throw new Error(`Failed to fetch media: ${fileResponse.statusText}`);
}
const contentLength = Number(
fileResponse.headers.get('content-length') || 0
);
const form = new FormDataUpload();
form.append('file', Readable.fromWeb(fileResponse.body as any), {
filename: fileUrl.split('/').pop()?.split('?')[0] || 'file',
...(contentLength ? { knownLength: contentLength } : {}),
});
if (alt) {
form.append('description', alt);
}
const mediaResponse = await fetch(`${instanceUrl}/api/v1/media`, {
method: 'POST',
headers: {
...form.getHeaders(),View on GitHub (pinned to 0f1647f749)
Solutions
- Verify the media file URL is publicly accessible (curl it from the server)
- Check storage config (S3 bucket policy / signed URL expiry / BACKEND_URL env)
- Re-add the media to the post from the media library and retry
Defensive patterns
Strategy: validation
Validate before calling
const res = await fetch(media.url, { method: 'HEAD' });
if (!res.ok) throw new Error(`Media URL not reachable (${res.status})`); Prevention
- Verify media URLs resolve publicly before scheduling
- Keep storage signed-URL TTL longer than max scheduling delay
When it happens
Trigger: fetch(media.url) (the uploaded file URL) returns !ok or no body — 404/403 on the storage URL, expired signed URL, or proxy returning an error page.
Common situations: Expired S3/cloud signed URLs, deleted media library file, misconfigured storage/CDN, or wrong public backend URL in env making media URLs unreachable.
Related errors
- Refresh token error
- The uploaded media expired before the post was published, pl
- The media took too long to process, please try again
- Could not determine the media size for upload
- Failed to fetch media: ${fileResponse.statusText}
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/866684ae6b7200cc.
Report an issue: GitHub.