{"record":{"id":"66842f43e5da4165","repo":"jackwener/OpenCLI","slug":"failed-to-unfollow-http-r2-status","errorCode":null,"errorMessage":"Failed to unfollow: HTTP ' + r2.status","messagePattern":"Failed to unfollow: HTTP ' \\+ r2\\.status","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clis/instagram/unfollow.js","lineNumber":33,"sourceCode":"        },\n    ],\n    columns: ['status', 'username'],\n    pipeline: [\n        { navigate: 'https://www.instagram.com' },\n        { evaluate: `(async () => {\n  const username = \\${{ args.username | json }};\n  const headers = { 'X-IG-App-ID': '936619743392459' };\n  const opts = { credentials: 'include', headers };\n\n  ${buildResolveInstagramUserIdJs()}\n\n  const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';\n  const r2 = await fetch('https://www.instagram.com/api/v1/friendships/destroy/' + userId + '/', {\n    method: 'POST',\n    credentials: 'include',\n    headers: { ...headers, 'X-CSRFToken': csrf, 'Content-Type': 'application/x-www-form-urlencoded' },\n  });\n  if (!r2.ok) throw new Error('Failed to unfollow: HTTP ' + r2.status);\n  let d2;\n  try {\n    d2 = await r2.json();\n  } catch {\n    throw new Error('Instagram unfollow returned invalid JSON');\n  }\n  if (!d2 || typeof d2 !== 'object' || d2.status !== 'ok') {\n    throw new Error('Instagram unfollow returned no success evidence');\n  }\n  return [{ status: 'Unfollowed', username }];\n})()\n` },\n    ],\n});\n","sourceCodeStart":15,"sourceCodeEnd":48,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/instagram/unfollow.js#L15-L48","documentation":"Thrown in clis/instagram/unfollow.js when the in-page POST to Instagram's friendships/destroy API returns a non-OK HTTP status. The request runs inside the browser context with session cookies and the CSRF token, so failures indicate Instagram rejected the unfollow (auth, rate limit, or bad user id).","triggerScenarios":"r2.ok is false on `fetch('https://www.instagram.com/api/v1/friendships/destroy/' + userId + '/', { method: 'POST', credentials: 'include', headers: { ..., 'X-CSRFToken': csrf } })` — e.g. 403 (missing/invalid CSRF or blocked), 404 (userId not found), 429 (rate limited).","commonSituations":"csrftoken cookie missing so the regex yields '' and Instagram returns 403, unfollowing too many users quickly (429), stale userId, or an expired session.","solutions":["Log the actual r2.status to distinguish 401/403 (auth/CSRF) from 404 (bad userId) from 429 (rate limit)","Re-login to refresh cookies and the csrftoken used to build X-CSRFToken","Verify userId is a valid numeric Instagram user id (resolve the username first if needed)","Slow down: add delays between unfollows to avoid rate limiting"],"exampleFix":"// before\nif (!r2.ok) throw new Error('Failed to unfollow: HTTP ' + r2.status);\n// after\nif (!r2.ok) {\n  if (r2.status === 429) throw new Error('Unfollow rate limited; wait before retrying');\n  throw new Error('Failed to unfollow: HTTP ' + r2.status + ' (check login and csrftoken)');\n}","handlingStrategy":"try-catch","validationCode":"const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';\nif (!csrf) throw new Error('No csrftoken cookie; log in before unfollowing');\nif (!/^\\\\d+$/.test(userId)) throw new Error(`Invalid numeric userId: ${userId}`);","typeGuard":"function isOkResponse(r) { return !!r && typeof r.status === 'number' && r.status >= 200 && r.status < 300; }","tryCatchPattern":"try {\n  await unfollow(username);\n} catch (e) {\n  if (/HTTP 403/.test(e.message)) { await relogin(); /* refresh csrf */ }\n  else if (/HTTP 429/.test(e.message)) { await sleep(60000); }\n  else if (/HTTP 404/.test(e.message)) { console.error('Unknown userId'); }\n  else throw e;\n}","preventionTips":["Ensure the csrftoken cookie exists before POSTing","Throttle unfollows with delays to avoid 429s","Resolve usernames to valid numeric user ids first","Re-login when cookies age out; detect 401/403 early"],"tags":["http","instagram","csrf","authentication"],"backgroundTag":"http-request-rejected","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}