jackwener/OpenCLI · error
${label} returned invalid JSON
Error message
${label} returned invalid JSON What it means
readInstagramJson wraps response.json(); when the response body cannot be parsed as JSON it rethrows '${label} returned invalid JSON'. This catches Instagram returning HTML (login pages, challenge pages) or empty bodies instead of the expected JSON API payload.
Source
Thrown at clis/instagram/comment.js:32
},
{ name: 'text', required: true, positional: true, help: 'Comment text' },
{ name: 'index', type: 'int', default: 1, help: 'Post index (1 = most recent)' },
],
columns: ['status', 'user', 'text'],
pipeline: [
{ navigate: 'https://www.instagram.com' },
{ evaluate: `(async () => {
const username = \${{ args.username | json }};
const commentText = \${{ args.text | 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');
return { pk };
}
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-authenticate / refresh Instagram session cookies so responses are API JSON, not login HTML
- Check the raw response text and Content-Type; if HTML, a login or challenge is being served
- Retry after backoff if the failure is transient (rate limiting/outage)
- Confirm the request path/headers (X-IG-App-ID, credentials: 'include') are intact
Example fix
// before
async function readInstagramJson(response, label) {
try { return await response.json(); }
catch { throw new Error(label + ' returned invalid JSON'); }
}
// after
async function readInstagramJson(response, label) {
const text = await response.text();
try { return JSON.parse(text); }
catch {
if (/login|challenge/i.test(text.slice(0, 500))) throw new Error(label + ': session expired, re-login required');
throw new Error(label + ' returned invalid JSON: ' + text.slice(0, 200));
}
} Defensive patterns
Strategy: try-catch
Validate before calling
const res = await fetch(url, opts);
const ct = res.headers.get('content-type') || '';
if (!ct.includes('application/json')) {
throw new Error('Expected JSON, got ' + ct + ' - session probably expired');
} Type guard
function isJsonResponse(res) {
return (res.headers.get('content-type') || '').includes('application/json');
} Try / catch
try {
await runCommentPipeline(args);
} catch (e) {
if (/returned invalid JSON/.test(e.message)) {
console.error('Instagram returned non-JSON (login/challenge page) - refresh cookies');
} else throw e;
} Prevention
- Refresh session cookies regularly
- Watch for HTML login/challenge pages served with 200
- Add content-type checks before res.json()
- Back off on repeated failures - may be rate limiting
When it happens
Trigger: A fetch (feed-by-username or comment add) resolves ok but the body is HTML — e.g. a login redirect page, consent/challenge interstitial, rate-limit HTML, or an empty 204-style response passed to res.json().
Common situations: Expired session cookies so IG serves the login page; account flagged for verification showing a challenge page; HTML error pages served during outages or heavy rate limiting.
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
- ${label} returned invalid JSON
- Instagram private route could not derive CSRF token from bro
- Instagram private publish configure_sidecar returned invalid
- Instagram story publish could not derive current user id fro
- HTTP ' + res.status + ' - make sure you are logged in to Ins
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/8383cc09007f1676.
Report an issue: GitHub.