gitroomhq/postiz-app · error · BadBody
Failed to upload the media file
Error message
Failed to upload the media file
What it means
The PUT of media bytes to Whop's upload_url returned a non-ok status. Because a rejected PUT leaves the file 'pending' forever, it fails fast with BadBody instead of burning the ~9-minute status poll.
Source
Thrown at libraries/nestjs-libraries/src/integrations/social/whop.provider.ts:296
});
if (!fileResponse.ok || !fileResponse.body) {
throw new Error(`Failed to fetch media: ${fileResponse.statusText}`);
}
const uploadResponse = await fetch(createFileResponse.upload_url, {
method: 'PUT',
headers: {
// Whop's own upload_headers win if they ever include a length.
'Content-Length': String(contentLength),
...(createFileResponse.upload_headers || {}),
},
body: fileResponse.body,
// Required by undici when streaming a request body.
duplex: 'half',
} as any);
// A rejected PUT leaves the file pending forever - fail fast instead
// of burning the ~9 minute status poll below.
if (!uploadResponse.ok) {
throw new BadBody(
this.identifier,
await uploadResponse.text().catch(() => '{}'),
'{}',
'Failed to upload the media file'
);
}
let uploadStatus = 'pending';
let attempts = 0;
const maxAttempts = 108; // ~9 minutes at 5s interval
while (uploadStatus !== 'ready') {
if (attempts++ >= maxAttempts) {
throw new Error('File upload timed out');
}
const fileStatus = await (
await this.fetch(
`https://api.whop.com/api/v1/files/${createFileResponse.id}`,View on GitHub (pinned to 0f1647f749)
Solutions
- Read the response text attached to the BadBody for Whop's rejection reason
- Ensure the Content-Length matches the actual byte stream being PUT (don't transcode/resize mid-flight)
- Retry the post to get a fresh upload_url
- Verify the file is within Whop's size/type limits
Defensive patterns
Strategy: retry
Validate before calling
if (contentLength !== actualBytes.length) { /* abort before PUT; sizes must match */ } Try / catch
catch (e) { if (e instanceof BadBody && e.message.includes('upload the media file')) { /* retry post for a fresh upload_url; inspect attached response text */ } throw e; } Prevention
- Stream exactly Content-Length bytes on the PUT
- Start the PUT promptly after obtaining upload_url
- Validate file type/size against Whop's limits before uploading
When it happens
Trigger: Whop's file upload endpoint rejects the PUT: expired upload_url, wrong Content-Length header (does not match actual streamed bytes), content-type mismatch, or size exceeding Whop's limit.
Common situations: Media file changed size between HEAD and PUT; Whop upload headers requirements changed; slow networks letting the signed upload_url expire before the PUT starts.
Related errors
- Could not determine the media size for upload
- Failed to fetch media: ${fileResponse.statusText}
- File upload timed out
- File upload failed
AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27).
Data as JSON: /api/errors/2691067d1a07d636.
Report an issue: GitHub.