{"record":{"id":"a2eaad7d932fb3c3","repo":"jackwener/OpenCLI","slug":"failed-to-fetch-followers-http-r2-status","errorCode":null,"errorMessage":"Failed to fetch followers: HTTP ' + r2.status","messagePattern":"Failed to fetch followers: HTTP ' \\+ r2\\.status","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/instagram/followers.js","lineNumber":29,"sourceCode":"        { name: 'limit', type: 'int', default: 20, help: 'Number of followers' },\n    ],\n    columns: ['rank', 'username', 'name', 'verified', 'private'],\n    pipeline: [\n        { navigate: 'https://www.instagram.com' },\n        { evaluate: `(async () => {\n  const username = \\${{ args.username | json }};\n  const limit = \\${{ args.limit }};\n  if (!Number.isInteger(limit) || limit < 1) throw new Error('limit must be a positive integer');\n  const headers = { 'X-IG-App-ID': '936619743392459' };\n  const opts = { credentials: 'include', headers };\n\n  ${buildResolveInstagramUserIdJs()}\n\n  const r2 = await fetch(\n    'https://www.instagram.com/api/v1/friendships/' + userId + '/followers/?count=' + limit,\n    opts\n  );\n  if (!r2.ok) throw new Error('Failed to fetch followers: HTTP ' + r2.status);\n  const d2 = await r2.json();\n  if (!d2 || typeof d2 !== 'object' || !Array.isArray(d2.users)) {\n    throw new Error('Instagram followers returned malformed users payload');\n  }\n  return d2.users.slice(0, limit).map((u, i) => {\n    if (!u || typeof u !== 'object') {\n      throw new Error('Instagram followers returned malformed user row');\n    }\n    const pkRaw = u.pk ?? u.pk_id ?? u.id;\n    const pk = typeof pkRaw === 'number' ? String(pkRaw) : (typeof pkRaw === 'string' ? pkRaw.trim() : '');\n    const usernameValue = typeof u.username === 'string' ? u.username.trim() : '';\n    if (!/^\\\\d+$/.test(pk) || !usernameValue) {\n      throw new Error('Instagram followers returned malformed user row');\n    }\n    return {\n      rank: i + 1,\n      username: usernameValue,\n      name: typeof u.full_name === 'string' ? u.full_name : '',","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/instagram/followers.js#L11-L47","documentation":"The followers command GETs https://www.instagram.com/api/v1/friendships/<userId>/followers/?count=<limit> with session credentials and the hardcoded X-IG-App-ID header. If the HTTP response status is not ok (4xx/5xx), the CLI throws this error carrying the status code. It means Instagram refused the followers request at the transport/status level before any payload validation.","triggerScenarios":"401/403 from missing or expired session cookies; 429 rate limited; 404 when userId resolved incorrectly; 5xx from Instagram side; request blocked by anti-bot challenge.","commonSituations":"Not logged into instagram.com in the browser session; scraping too many followers rapidly (429); private/deleted account yielding 404/403; IG App-ID header no longer accepted after Instagram frontend update.","solutions":["Log into instagram.com in the browser session to restore cookies (401/403).","Back off and retry after delays; reduce request rate / limit to avoid 429.","Verify the target username resolves to the right userId (404 suggests bad id).","Check whether Instagram changed the required X-IG-App-ID or endpoint and update the hardcoded header."],"exampleFix":"// before\nif (!r2.ok) throw new Error('Failed to fetch followers: HTTP ' + r2.status);\n// after (caller-side backoff)\ntry { await listFollowers(user, limit); }\ncatch (e) {\n  const m = /HTTP (\\d+)/.exec(e.message);\n  if (m && m[1] === '429') await sleep(60000);\n  else throw e;\n}","handlingStrategy":"retry","validationCode":"// Pre-flight session check before fetching followers:\nconst authed = document.cookie.includes('ds_user_id');\nif (!authed) throw new Error('Log into instagram.com first (would get HTTP 401/403)');","typeGuard":null,"tryCatchPattern":"async function withRetry(fn, tries = 3) {\n  for (let i = 0; i < tries; i++) {\n    try { return await fn(); }\n    catch (e) {\n      const m = /HTTP (\\d+)/.exec(String(e.message));\n      const code = m && +m[1];\n      if (code === 429 || code >= 500) { await new Promise(r => setTimeout(r, 2 ** i * 1000)); continue; }\n      throw e;\n    }\n  }\n  throw new Error('retries exhausted');\n}","preventionTips":["Maintain a valid logged-in session before bulk reads.","Throttle follower scraping; back off on 429 with exponential delays.","Validate usernames resolve to userIds before hitting the friendships endpoint.","Watch for Instagram App-ID/endpoint changes; pin and monitor the hardcoded header."],"tags":["instagram","network","http-status","rate-limit","authentication"],"backgroundTag":"http-error-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}