{"record":{"id":"d57677dc822ee9d3","repo":"jackwener/OpenCLI","slug":"instagram-reel-upload-failed","errorCode":null,"errorMessage":"Instagram reel upload failed","messagePattern":"Instagram reel upload failed","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/instagram/reel.js","lineNumber":214,"sourceCode":"    (() => {\n      const input = document.querySelector(${JSON.stringify(selector)});\n      if (!(input instanceof HTMLInputElement)) return { count: null };\n      return { count: input.files?.length || 0 };\n    })()\n  `);\n    if (result?.count === null || result?.count === undefined)\n        return null;\n    return Number(result.count);\n}\nasync function waitForVideoPreview(page, maxWaitSeconds = 20) {\n    let lastDetail = '';\n    for (let attempt = 0; attempt < maxWaitSeconds * 2; attempt += 1) {\n        const result = await page.evaluate(buildInspectUploadStageJs());\n        lastDetail = String(result?.detail || '').trim();\n        if (result?.state === 'preview')\n            return;\n        if (result?.state === 'failed') {\n            throw new CommandExecutionError('Instagram reel upload failed', result.detail ? `Instagram rejected the reel upload: ${result.detail}` : 'Instagram rejected the reel upload before the preview stage');\n        }\n        if (attempt < maxWaitSeconds * 2 - 1)\n            await page.wait({ time: 0.5 });\n    }\n    await page.screenshot({ path: '/tmp/instagram_reel_preview_debug.png' });\n    throw new CommandExecutionError('Instagram reel preview did not appear after upload', lastDetail\n        ? `Inspect /tmp/instagram_reel_preview_debug.png. Last visible dialog text: ${lastDetail}`\n        : 'Inspect /tmp/instagram_reel_preview_debug.png for the upload state');\n}\nasync function clickAction(page, labels, scope = 'any') {\n    const result = await page.evaluate(buildClickActionJs(labels, scope));\n    if (!result?.ok) {\n        throw new CommandExecutionError(`Instagram action button not found: ${labels.join(' / ')}`);\n    }\n    return result.label || labels[0] || '';\n}\nasync function clickActionMaybe(page, labels, scope = 'any') {\n    const result = await page.evaluate(buildClickActionJs(labels, scope));","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/instagram/reel.js#L196-L232","documentation":"waitForVideoPreview polls the Instagram upload dialog every 0.5s for up to maxWaitSeconds and returns once the DOM reaches the 'preview' state. If the page reports state 'failed', it throws CommandExecutionError('Instagram reel upload failed') with Instagram's own dialog detail as secondary message. This means Instagram itself rejected the video before the preview stage was reached.","triggerScenarios":"page.evaluate(buildInspectUploadStageJs()) returns {state:'failed'} during the post-upload polling loop in waitForVideoPreview, i.e. Instagram rendered an explicit failure/rejection dialog instead of the video preview.","commonSituations":"Video violates Instagram reel specs (duration, aspect ratio, codec, size); file upload was truncated by a flaky network; Instagram rate-limits or flags the account/session; a logged-out or blocked session shows an error dialog; Instagram UI change makes the stage detector classify a transient error dialog as 'failed'.","solutions":["Read the secondary detail message — it contains Instagram's dialog text telling you exactly why the upload was rejected.","Re-encode the video to Instagram reel requirements: MP4/H.264, AAC audio, 9:16 up to 1080x1920, under ~90s and under ~4GB.","Retry with a fresh, logged-in browser session and check the account isn't rate-limited or action-blocked.","Inspect /tmp/instagram_reel_preview_debug.png (thrown on timeout) and increase maxWaitSeconds if the rejection is really a slow upload.","Re-run after verifying network stability; retry transient upload failures before assuming content rejection."],"exampleFix":"// before\nawait cli.uploadReel('clip.mov'); // QuickTime MOV, rejected by Instagram\n// after\nawait transcodeToMp4H264('clip.mov', 'clip.mp4');\nawait cli.uploadReel('clip.mp4');","handlingStrategy":"retry","validationCode":"// Pre-validate the video before uploading\nimport { stat } from 'node:fs/promises';\nasync function assertReelCompatible(path, durationSec) {\n  const { size } = await stat(path);\n  if (!path.toLowerCase().endsWith('.mp4')) throw new Error('Reels must be MP4/H.264');\n  if (size > 4 * 1024 ** 3) throw new Error('Reel exceeds ~4GB limit');\n  if (durationSec > 90) throw new Error('Reel exceeds 90s limit');\n}","typeGuard":"function isUploadStageResult(r) {\n  return !!r && typeof r === 'object' &&\n    (r.state === 'preview' || r.state === 'failed') &&\n    (r.detail === undefined || typeof r.detail === 'string');\n}","tryCatchPattern":"try {\n  await waitForVideoPreview(page, maxWaitSeconds);\n} catch (err) {\n  if (String(err.message).includes('reel upload failed')) {\n    console.error('Instagram rejected upload:', err.secondary || err.message);\n    // fix media/session, then retry once with a fresh session\n  } else throw err;\n}","preventionTips":["Always transcode to MP4/H.264/AAC within reel specs before upload","Check the secondary detail message — it quotes Instagram's own rejection reason","Retry once on a fresh session to distinguish transient vs content rejection","Watch account rate limits; back off after multiple rejected posts"],"tags":["instagram","upload","puppeteer","automation"],"backgroundTag":"upload-rejected","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}