← back to Norma
TK-10395: bounded retry-on-2207076 in reel skill (Meta transient media-upload failure)
989701195fd4bcbba3a008f303b318ec3edb8dee · 2026-08-10 08:13:02 -0700 · Steve Abrams
createContainer+waitForContainer now retry up to 3x on IG error 2207076 / 'Media upload has failed' / processing-timeout; publish only fires after a FINISHED container so retry is double-post-safe. Approved by Steve.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M agents/instagram-agent/skills/reel.js
Diff
commit 989701195fd4bcbba3a008f303b318ec3edb8dee
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 10 08:13:02 2026 -0700
TK-10395: bounded retry-on-2207076 in reel skill (Meta transient media-upload failure)
createContainer+waitForContainer now retry up to 3x on IG error 2207076 / 'Media upload has failed' / processing-timeout; publish only fires after a FINISHED container so retry is double-post-safe. Approved by Steve.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
agents/instagram-agent/skills/reel.js | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/agents/instagram-agent/skills/reel.js b/agents/instagram-agent/skills/reel.js
index 5053d20..9ba15f8 100644
--- a/agents/instagram-agent/skills/reel.js
+++ b/agents/instagram-agent/skills/reel.js
@@ -125,13 +125,30 @@ module.exports = async function reel(params) {
};
if (params.cover_url) containerBody.cover_url = params.cover_url;
- const containerId = await ig.createContainer(igUserId, accessToken, containerBody);
- console.log(`[${AGENT}] Reel container created: ${containerId} — waiting for processing...`);
-
- // Step 2: video must finish processing before it can be published
- await ig.waitForContainer(containerId, accessToken);
+ // Steps 1+2: create container + wait for processing, with a bounded retry on
+ // transient Meta-side processing failures (IG error 2207076 "Media upload has
+ // failed" — Meta advises retry; TK-10395 root-cause). Container creation is
+ // PRE-publish, so retrying a FAILED container can never cause a double-post.
+ const MAX_ATTEMPTS = 3;
+ let containerId;
+ for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
+ containerId = await ig.createContainer(igUserId, accessToken, containerBody);
+ console.log(`[${AGENT}] Reel container created: ${containerId} — waiting for processing... (attempt ${attempt}/${MAX_ATTEMPTS})`);
+ try {
+ await ig.waitForContainer(containerId, accessToken);
+ break; // FINISHED — safe to publish
+ } catch (e) {
+ const transient = /2207076|Media upload has failed|did not finish processing/i.test(e.message || '');
+ if (attempt < MAX_ATTEMPTS && transient) {
+ console.warn(`[${AGENT}] container processing failed (${e.message}) — retrying in ${5 * attempt}s (attempt ${attempt}/${MAX_ATTEMPTS})`);
+ await new Promise((r) => setTimeout(r, 5000 * attempt));
+ continue;
+ }
+ throw e;
+ }
+ }
- // Step 3: publish
+ // Step 3: publish (only reached once a container reported FINISHED)
const mediaId = await ig.publishContainer(igUserId, accessToken, containerId);
const permalink = await ig.permalinkOf(mediaId, accessToken);
console.log(`[${AGENT}] Reel published (account=${account}): media=${mediaId} ${permalink || ''}`);
← cbfbf08 Norma pre-deploy gate: run durable smoke battery before any
·
back to Norma
·
TK-10395: cap reel container poll at 12x4s so 3x-retry worst 564be77 →