{"record":{"id":"1ca3cfaca2ce4bc0","repo":"gitroomhq/postiz-app","slug":"x-failed-to-process-the-uploaded-video-processing","errorCode":null,"errorMessage":"X failed to process the uploaded video${processing?.error?.message ? `: ${processing.error.message}` : ''}","messagePattern":"X failed to process the uploaded video(.+?)` : ''\\}","errorType":"exception","errorClass":"BadBody","httpStatus":null,"severity":"error","filePath":"libraries/nestjs-libraries/src/integrations/social/x.provider.ts","lineNumber":616,"sourceCode":"      };\n    }>('media/upload', { command: 'STATUS', media_id: mediaId });\n\n    return status.data.processing_info;\n  }\n\n  // Blocking processing wait, used by the paths that still resolve everything\n  // inside one activity (comments, and post() for pre-v1.0.6 workflows).\n  private async waitForMediaProcessing(client: TwitterApi, mediaId: string) {\n    // X drives the pace via check_after_secs; cap on accumulated wait time\n    // (long videos can legitimately process for many minutes) instead of an\n    // attempt count, but never poll forever.\n    let waitedMs = 0;\n    const maxWaitMs = 7 * 60 * 1000;\n    let processing = await this.mediaProcessingStatus(client, mediaId);\n\n    while (processing && processing.state !== 'succeeded') {\n      if (processing.state === 'failed' || waitedMs >= maxWaitMs) {\n        throw new BadBody(\n          this.identifier,\n          JSON.stringify(processing),\n          Buffer.from('{}'),\n          `X failed to process the uploaded video${\n            processing?.error?.message ? `: ${processing.error.message}` : ''\n          }`\n        );\n      }\n\n      const waitMs = (processing.check_after_secs || 1) * 1000;\n      await timer(waitMs);\n      waitedMs += waitMs;\n      processing = await this.mediaProcessingStatus(client, mediaId);\n    }\n  }\n\n  // With ten X activities running concurrently (maxConcurrentJob), a user\n  // publishing several posts at the same minute can 429 on the upload","sourceCodeStart":598,"sourceCodeEnd":634,"githubUrl":"https://github.com/gitroomhq/postiz-app/blob/0f1647f7491a217d43eb5ae7a480484bdf0aff3e/libraries/nestjs-libraries/src/integrations/social/x.provider.ts#L598-L634","documentation":"waitForMediaProcessing polls X's media processing status after an upload (INIT/APPEND/FINALIZE or status check); it throws when state is 'failed' or when 7 minutes elapse without 'succeeded'.","triggerScenarios":"GET media/upload.json?command=STATUS keeps returning in_progress for 7 minutes, or returns state 'failed' (transcode error, too-long video, invalid media).","commonSituations":"Long/high-bitrate videos on busy X transcoders; rate-limited STATUS polling; media at the edge of X's limits that processes slowly then fails.","solutions":["Shorten/compress the video and retry","Check processing_info.error in the error body for the specific X failure reason","Retry the post — transient transcoder delays are common near the 7-minute cap","If it consistently times out only for one file, the file itself is the problem: re-encode it"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"const isTerminalOrSlow = (state?: string, waitedMs: number) => state === 'failed' || waitedMs >= 7 * 60 * 1000;","tryCatchPattern":"catch (e) { if (e instanceof BadBody && e.message.includes('process the uploaded video')) { /* safe to retry: tweet not yet created */ } throw e; }","preventionTips":["Compress long videos so processing finishes well under 7 minutes","Retry once on timeout — the post is not created yet","Watch X's transcoder status during incidents before scheduling video posts"],"tags":["x-twitter","media-processing","polling-timeout","transcode"],"backgroundTag":"social-media-publish-timeout","analyzedSha":"0f1647f7491a217d43eb5ae7a480484bdf0aff3e","analyzedAt":"2026-08-27T12:09:55.020Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}