jackwener/OpenCLI · error
Failed to unsave: HTTP ' + r2.status
Error message
Failed to unsave: HTTP ' + r2.status
What it means
The unsave POST /api/v1/web/save/{pk}/unsave/ returned a non-2xx HTTP status. This is a transport-level failure before the body contract is even checked — typically 401/403 for auth or 429 for rate limiting. The status code is included in the message.
Source
Thrown at clis/instagram/unsave.js:61
return { pk, caption };
}
function assertOkStatus(payload, label) {
if (!payload || typeof payload !== 'object' || payload.status !== 'ok') {
throw new Error(label + ' returned no success evidence');
}
}
// web_profile_info answers HTTP 400 for business accounts; feed-by-username needs no user id. See #2234.
const r1 = await fetch('https://www.instagram.com/api/v1/feed/user/' + encodeURIComponent(username) + '/username/?count=' + (idx + 1), opts);
if (!r1.ok) throw new Error(r1.status === 404 ? 'User not found: ' + username : 'HTTP ' + r1.status + ' - make sure you are logged in to Instagram');
const { pk, caption } = getPostFromFeed(await readInstagramJson(r1, 'Instagram feed-by-username'), 'Instagram feed-by-username');
const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';
const r2 = await fetch('https://www.instagram.com/api/v1/web/save/' + pk + '/unsave/', {
method: 'POST', credentials: 'include',
headers: { ...headers, 'X-CSRFToken': csrf, 'Content-Type': 'application/x-www-form-urlencoded' },
});
if (!r2.ok) throw new Error('Failed to unsave: HTTP ' + r2.status);
assertOkStatus(await readInstagramJson(r2, 'Instagram unsave'), 'Instagram unsave');
return [{ status: 'Unsaved', user: username, post: caption || '(post #' + (idx+1) + ')' }];
})()
` },
],
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Re-login in the browser profile to refresh sessionid and csrftoken, then retry.
- If status is 429, wait (minutes to hours) and reduce request rate.
- Confirm csrftoken cookie exists before the call and is sent as X-CSRFToken.
Example fix
// before
const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';
// after
const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1];
if (!csrf) throw new Error('Not logged in: csrftoken cookie missing'); Defensive patterns
Strategy: retry
Validate before calling
if (!document.cookie.includes('csrftoken') || !document.cookie.includes('sessionid')) {
throw new Error('Instagram session cookies missing — log in first');
} Try / catch
try {
await cli.unsave(user, index);
} catch (e) {
const m = e.message.match(/HTTP (\d+)/);
if (m && m[1] === '429') { await delay(15 * 60_000); return retry(); }
if (m && (m[1] === '401' || m[1] === '403')) { await relogin(); return retry(); }
throw e;
} Prevention
- Keep the browser profile logged in
- Back off on 429 before retrying
- Refresh cookies after password changes or logouts elsewhere
When it happens
Trigger: Session cookies expired (401/403), CSRF token mismatch, or unsave throttling (429) on the POST.
Common situations: Long-lived CLI profile where Instagram rotated the session; bulk unsaving triggering 429; missing csrftoken cookie so the request is rejected.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- HTTP ' + res.status + ' - make sure you are logged in to Ins
- HTTP ' + r2.status + ' - make sure you are logged in to Inst
- ${label} failed: HTTP ${response.status}
- HTTP ${result.httpStatus} from Instagram /users/info
- Failed to follow: HTTP ' + r2.status
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1d93ace89467e25e.
Report an issue: GitHub.