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
- 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.
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
- 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
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
- Instagram reel preview did not appear after upload
- Instagram reel editor did not appear
- Instagram reel ${expected} editor did not appear
- Instagram post feed returned malformed items for ${username}
- Could not find the like control on ${post.code}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/d57677dc822ee9d3.
Report an issue: GitHub.