jackwener/OpenCLI · error
returned invalid JSON
Error message
returned invalid JSON
What it means
The `readInstagramJson` helper wraps `response.json()` for Instagram API responses; when the body cannot be parsed as JSON, it rethrows with the endpoint label plus this message (e.g. 'Instagram feed-by-username returned invalid JSON'). Instagram frequently returns HTML (login pages, rate-limit/challenge pages) with an HTTP 200, so this error surfaces whenever the feed-by-username or save endpoint's body is not JSON.
Source
Thrown at clis/instagram/save.js:30
positional: true,
help: 'Username of the post author',
},
{ name: 'index', type: 'int', default: 1, help: 'Post index (1 = most recent)' },
],
columns: ['status', 'user', 'post'],
pipeline: [
{ navigate: 'https://www.instagram.com' },
{ evaluate: `(async () => {
const username = \${{ args.username | json }};
const idx = \${{ args.index }} - 1;
if (!Number.isInteger(idx) || idx < 0) throw new Error('index must be a positive integer');
const headers = { 'X-IG-App-ID': '936619743392459' };
const opts = { credentials: 'include', headers };
async function readInstagramJson(response, label) {
try {
return await response.json();
} catch {
throw new Error(label + ' returned invalid JSON');
}
}
function getPostFromFeed(feed, label) {
if (!feed || typeof feed !== 'object' || !Array.isArray(feed.items)) {
throw new Error(label + ' returned malformed items payload');
}
if (idx >= feed.items.length) throw new Error('Post index ' + (idx + 1) + ' not found');
const post = feed.items[idx];
const pkRaw = post?.pk ?? post?.id;
const pk = typeof pkRaw === 'number' ? String(pkRaw) : (typeof pkRaw === 'string' ? pkRaw.trim() : '');
if (!/^\\d+$/.test(pk)) throw new Error(label + ' returned malformed post row');
const caption = typeof post?.caption?.text === 'string' ? post.caption.text.substring(0, 60) : '';
return { pk, caption };
}
function assertOkStatus(payload, label) {
if (!payload || typeof payload !== 'object' || payload.status !== 'ok') {
throw new Error(label + ' returned no success evidence');
}View on GitHub (pinned to 49907e53dc)
Solutions
- Re-login to Instagram in the browser profile the CLI drives (refresh the session cookies), then retry.
- Wait and retry later if rate-limited — the response is a challenge/HTML page, not JSON.
- Check whether a proxy, VPN, or corporate firewall is intercepting requests to instagram.com and returning HTML.
- Retry the command once; transient HTML error pages sometimes resolve on a second attempt.
Example fix
// trigger a fresh login before running the command // before instagram save someuser --index 1 // -> 'Instagram feed-by-username returned invalid JSON' // after open browser profile -> log into instagram.com -> retry: instagram save someuser --index 1
Defensive patterns
Strategy: try-catch
Try / catch
try {
await run(['instagram', 'save', username, '--index', String(i)]);
} catch (e) {
if (String(e.message).includes('returned invalid JSON')) {
// session likely expired or HTML challenge page returned
await refreshInstagramLogin();
return retryWithBackoff(() => run(['instagram', 'save', username, '--index', String(i)]), { attempts: 2 });
}
throw e;
} Prevention
- Keep the CLI browser profile's Instagram session fresh; re-login periodically.
- Don't loop the command rapidly — rate limits cause HTML challenge pages.
- Disable interfering proxies/VPN for instagram.com traffic.
When it happens
Trigger: Calling GET /api/v1/feed/user/<username>/username/ or POST /api/v1/web/save/<pk>/save/ from an authenticated browser context where the response body is HTML instead of JSON: a session-expiry redirect to the login page, a rate-limit/challenge interstitial, or an empty/HTML error page returned with status 200.
Common situations: Instagram session cookies have expired so the fetch lands on the login HTML page; the account hit a rate limit or 'Try again later' challenge; a proxy/corporate gateway intercepts the request and returns an HTML block page; Instagram A/B changes the response shape or returns an empty body on 200.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- returned invalid JSON
- Instagram whoami failed: ${result.detail}
- Failed to fetch followers: HTTP ' + r2.status
- ${label} returned invalid JSON
- User not found: ' + username : 'HTTP ' + r1.status + ' - mak
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5921042cfcd03aca.
Report an issue: GitHub.