[object Object]

← 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

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 →