jackwener/OpenCLI · error · CommandExecutionError

Instagram reel upload failed

Error message

Instagram reel upload failed

What it means

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.

Source

Thrown at clis/instagram/reel.js:214

    (() => {
      const input = document.querySelector(${JSON.stringify(selector)});
      if (!(input instanceof HTMLInputElement)) return { count: null };
      return { count: input.files?.length || 0 };
    })()
  `);
    if (result?.count === null || result?.count === undefined)
        return null;
    return Number(result.count);
}
async function waitForVideoPreview(page, maxWaitSeconds = 20) {
    let lastDetail = '';
    for (let attempt = 0; attempt < maxWaitSeconds * 2; attempt += 1) {
        const result = await page.evaluate(buildInspectUploadStageJs());
        lastDetail = String(result?.detail || '').trim();
        if (result?.state === 'preview')
            return;
        if (result?.state === 'failed') {
            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');
        }
        if (attempt < maxWaitSeconds * 2 - 1)
            await page.wait({ time: 0.5 });
    }
    await page.screenshot({ path: '/tmp/instagram_reel_preview_debug.png' });
    throw new CommandExecutionError('Instagram reel preview did not appear after upload', lastDetail
        ? `Inspect /tmp/instagram_reel_preview_debug.png. Last visible dialog text: ${lastDetail}`
        : 'Inspect /tmp/instagram_reel_preview_debug.png for the upload state');
}
async function clickAction(page, labels, scope = 'any') {
    const result = await page.evaluate(buildClickActionJs(labels, scope));
    if (!result?.ok) {
        throw new CommandExecutionError(`Instagram action button not found: ${labels.join(' / ')}`);
    }
    return result.label || labels[0] || '';
}
async function clickActionMaybe(page, labels, scope = 'any') {
    const result = await page.evaluate(buildClickActionJs(labels, scope));

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the secondary detail message — it contains Instagram's dialog text telling you exactly why the upload was rejected.
  2. Re-encode the video to Instagram reel requirements: MP4/H.264, AAC audio, 9:16 up to 1080x1920, under ~90s and under ~4GB.
  3. Retry with a fresh, logged-in browser session and check the account isn't rate-limited or action-blocked.
  4. Inspect /tmp/instagram_reel_preview_debug.png (thrown on timeout) and increase maxWaitSeconds if the rejection is really a slow upload.
  5. Re-run after verifying network stability; retry transient upload failures before assuming content rejection.

Example fix

// before
await cli.uploadReel('clip.mov'); // QuickTime MOV, rejected by Instagram
// after
await transcodeToMp4H264('clip.mov', 'clip.mp4');
await cli.uploadReel('clip.mp4');
Defensive patterns

Strategy: retry

Validate before calling

// Pre-validate the video before uploading
import { stat } from 'node:fs/promises';
async function assertReelCompatible(path, durationSec) {
  const { size } = await stat(path);
  if (!path.toLowerCase().endsWith('.mp4')) throw new Error('Reels must be MP4/H.264');
  if (size > 4 * 1024 ** 3) throw new Error('Reel exceeds ~4GB limit');
  if (durationSec > 90) throw new Error('Reel exceeds 90s limit');
}

Type guard

function isUploadStageResult(r) {
  return !!r && typeof r === 'object' &&
    (r.state === 'preview' || r.state === 'failed') &&
    (r.detail === undefined || typeof r.detail === 'string');
}

Try / catch

try {
  await waitForVideoPreview(page, maxWaitSeconds);
} catch (err) {
  if (String(err.message).includes('reel upload failed')) {
    console.error('Instagram rejected upload:', err.secondary || err.message);
    // fix media/session, then retry once with a fresh session
  } else throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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'.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/d57677dc822ee9d3. Report an issue: GitHub.