← back to Dw Marketing Reels
publish-ig.mjs: refuse non-postable accounts at the resolver with a clear reason (TK-10447)
c396f4bf51447bd6b6c15e89646aad48ee72d3a8 · 2026-08-25 14:45:11 -0700 · Steve Abrams
The roster demotion protected the console UI but NOT the publish script: resolveAccountUid
still resolved grasscloth's ig_user_id (present but unreachable), so a cron/retry/manual
--account ig-grassclothwallpaper would march into the Graph post and fail with an opaque
'Object does not exist'. Now the resolver carries status and the publish path hard-fails
BEFORE the media/Graph calls on any status != ready, printing the real reason.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit c396f4bf51447bd6b6c15e89646aad48ee72d3a8
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Aug 25 14:45:11 2026 -0700
publish-ig.mjs: refuse non-postable accounts at the resolver with a clear reason (TK-10447)
The roster demotion protected the console UI but NOT the publish script: resolveAccountUid
still resolved grasscloth's ig_user_id (present but unreachable), so a cron/retry/manual
--account ig-grassclothwallpaper would march into the Graph post and fail with an opaque
'Object does not exist'. Now the resolver carries status and the publish path hard-fails
BEFORE the media/Graph calls on any status != ready, printing the real reason.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
scripts/publish-ig.mjs | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/scripts/publish-ig.mjs b/scripts/publish-ig.mjs
index aa8fffa..e2c21fe 100644
--- a/scripts/publish-ig.mjs
+++ b/scripts/publish-ig.mjs
@@ -40,11 +40,11 @@ function resolveAccountUid(sel) {
const load = f => { try { return JSON.parse(readFileSync(join(ROOT, 'data', f), 'utf8')); } catch { return null; } };
const managed = load('ig-accounts.json') || [];
const m = managed.find(a => String(a.id).toLowerCase() === key || String(a.handle || '').toLowerCase() === key);
- if (m && m.ig_user_id) return { uid: m.ig_user_id, label: m.label || m.handle };
+ if (m && m.ig_user_id) return { uid: m.ig_user_id, label: m.label || m.handle, status: m.status, note: m.note };
const canon = (load('dw-canonical-accounts.json') || {}).accounts || [];
const c = canon.find(a => String(a.handle || '').toLowerCase() === key
|| 'ig-' + String(a.handle || '').toLowerCase().replace(/[^a-z0-9-]+/g, '-') === key);
- if (c && c.ig_user_id) return { uid: c.ig_user_id, label: c.name || c.handle };
+ if (c && c.ig_user_id) return { uid: c.ig_user_id, label: c.name || c.handle, status: 'ready' };
return null;
}
@@ -78,7 +78,14 @@ if (!tok) die('IG_ACCESS_TOKEN not found (env or Norma agent .env)');
const selected = argAccount || reel.igAccount || '';
const acct = resolveAccountUid(selected);
let acctLabel = 'env default (main DW)';
-if (acct) { uid = acct.uid; acctLabel = acct.label; }
+if (acct) {
+ // Refuse non-postable accounts BEFORE the media/Graph calls, with the real reason —
+ // otherwise the ig_user_id resolves but the Graph post fails with an opaque
+ // "Object does not exist" (e.g. @grassclothwallpaper, unlinked from the Page; TK-10447).
+ if (acct.status && acct.status !== 'ready')
+ die(`account "${selected}" is not postable (status: ${acct.status}). ${acct.note || 'Re-link/create it in Meta Business Manager, then re-run scripts/build-ig-accounts.js.'}`);
+ uid = acct.uid; acctLabel = acct.label;
+}
else if (selected) die(`account not resolvable to an ig_user_id: ${selected}`);
if (!uid) die('IG_USER_ID not found (no account selected and no env IG_USER_ID)');
const mediaUrl = `${PUBLIC_BASE}/reels/${encodeURIComponent(reel.file)}`;
← 0537a8a auto-data-snapshot: 2026-08-25T14:34:54 (1 data files) — dat
·
back to Dw Marketing Reels
·
auto-data-snapshot: 2026-08-25T17:39:55 (1 data files) — dat 9b8ae10 →