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

  1. Verify the media file URL is publicly accessible (curl it from the server)
  2. Check storage config (S3 bucket policy / signed URL expiry / BACKEND_URL env)
  3. 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

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


AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27). Data as JSON: /api/errors/866684ae6b7200cc. Report an issue: GitHub.