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

  1. Re-login to Instagram in the browser profile the CLI drives (refresh the session cookies), then retry.
  2. Wait and retry later if rate-limited — the response is a challenge/HTML page, not JSON.
  3. Check whether a proxy, VPN, or corporate firewall is intercepting requests to instagram.com and returning HTML.
  4. 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

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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/5921042cfcd03aca. Report an issue: GitHub.