{"record":{"id":"fe954e5ac0fefe05","repo":"jackwener/OpenCLI","slug":"failed-to-save-http-r2-status","errorCode":null,"errorMessage":"Failed to save: HTTP ' + r2.status","messagePattern":"Failed to save: HTTP ' \\+ r2\\.status","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clis/instagram/save.js","lineNumber":61,"sourceCode":"    return { pk, caption };\n  }\n  function assertOkStatus(payload, label) {\n    if (!payload || typeof payload !== 'object' || payload.status !== 'ok') {\n      throw new Error(label + ' returned no success evidence');\n    }\n  }\n\n  // web_profile_info answers HTTP 400 for business accounts; feed-by-username needs no user id. See #2234.\n  const r1 = await fetch('https://www.instagram.com/api/v1/feed/user/' + encodeURIComponent(username) + '/username/?count=' + (idx + 1), opts);\n  if (!r1.ok) throw new Error(r1.status === 404 ? 'User not found: ' + username : 'HTTP ' + r1.status + ' - make sure you are logged in to Instagram');\n  const { pk, caption } = getPostFromFeed(await readInstagramJson(r1, 'Instagram feed-by-username'), 'Instagram feed-by-username');\n\n  const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';\n  const r2 = await fetch('https://www.instagram.com/api/v1/web/save/' + pk + '/save/', {\n    method: 'POST', 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 save: HTTP ' + r2.status);\n  assertOkStatus(await readInstagramJson(r2, 'Instagram save'), 'Instagram save');\n  return [{ status: 'Saved', user: username, post: caption || '(post #' + (idx+1) + ')' }];\n})()\n` },\n    ],\n});\n","sourceCodeStart":43,"sourceCodeEnd":68,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/instagram/save.js#L43-L68","documentation":"Thrown when the save POST (POST /api/v1/web/save/<pk>/save/) returns a non-2xx HTTP status. Unlike the feed request, there is no special 404 branch — any failure status is reported as 'Failed to save: HTTP <status>'. Typical causes are an invalid/missing CSRF token (403), an expired session (401/403), rate limiting (429), or a bad pk (404).","triggerScenarios":"POSTing to /api/v1/web/save/<pk>/save/ when the `csrftoken` cookie is absent or expired (regex match fails, empty CSRF sent -> 403), the session cookies are stale (401), the pk is invalid (404), or the account is rate-limited/flagged (429).","commonSituations":"Session recently expired so document.cookie has no csrftoken; Instagram rotates the CSRF token mid-session; automation heuristics block the write action; saving posts in a rapid loop triggers 429.","solutions":["Re-login to Instagram in the CLI's browser profile to restore the session and a valid csrftoken cookie, then retry.","If 403, confirm a non-empty csrftoken is present (check document.cookie in the driven browser); a fresh page load of instagram.com usually (re)sets it.","If 429, wait before retrying and avoid batch-saving many posts back-to-back.","If 404, re-run the command — the pk comes from a fresh feed fetch, so a stale/cached invocation may reference a deleted post."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await run(['instagram', 'save', username, '--index', String(i)]);\n} catch (e) {\n  const m = String(e.message).match(/Failed to save: HTTP (\\d+)/);\n  if (m) {\n    const status = Number(m[1]);\n    if (status === 401 || status === 403) await refreshInstagramLogin(); // restore session + csrftoken\n    if (status === 429) await sleep(5 * 60_000);\n    return retryOnce(() => run(['instagram', 'save', username, '--index', String(i)]));\n  }\n  throw e;\n}","preventionTips":["Load instagram.com (fresh page) before write operations so the csrftoken cookie is set.","Re-login when session cookies age out; 401/403 are almost always session/CSRF issues.","Rate-limit batch saves to avoid 429s."],"tags":["csrf","http-error","authentication","instagram"],"backgroundTag":"http-403-forbidden","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}