jackwener/OpenCLI · error · CommandExecutionError

Instagram private publish configure_sidecar returned invalid

Error message

Instagram private publish configure_sidecar returned invalid JSON

What it means

publishSidecarWithRetry POSTs to https://www.instagram.com/api/v1/media/configure_sidecar/ and JSON.parses the raw response body. When the body is non-empty but not valid JSON (HTML login page, rate-limit page, proxy interstitial, garbage body), the parse throws and the library converts it into this CommandExecutionError instead of leaking a raw SyntaxError.

Source

Thrown at clis/instagram/_shared/private-publish.js:854

async function publishSidecarWithRetry(input) {
    const waitMs = input.waitMs ?? sleep;
    const requestInit = {
        method: 'POST',
        headers: {
            ...buildPrivateApiHeaders(input.apiContext),
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(input.payload),
    };
    for (let attempt = 0; attempt < INSTAGRAM_PRIVATE_SIDECAR_TRANSCODE_ATTEMPTS; attempt += 1) {
        const response = await input.fetcher('https://www.instagram.com/api/v1/media/configure_sidecar/', requestInit);
        const text = await response.text();
        let json = {};
        try {
            json = text ? JSON.parse(text) : {};
        }
        catch {
            throw new CommandExecutionError('Instagram private publish configure_sidecar returned invalid JSON');
        }
        if (!response.ok) {
            const detail = text ? ` ${text.slice(0, 500)}` : '';
            throw new CommandExecutionError(`Instagram private publish configure_sidecar failed: ${response.status}${detail}`);
        }
        const message = String(json?.message || '');
        if (response.status === 202
            || /transcode not finished yet/i.test(message)) {
            if (attempt >= INSTAGRAM_PRIVATE_SIDECAR_TRANSCODE_ATTEMPTS - 1) {
                throw new CommandExecutionError('Instagram private publish configure_sidecar timed out waiting for video transcode', text.slice(0, 500));
            }
            await waitMs(INSTAGRAM_PRIVATE_SIDECAR_TRANSCODE_WAIT_MS);
            continue;
        }
        if (String(json?.status || '').toLowerCase() === 'fail') {
            throw new CommandExecutionError('Instagram private publish configure_sidecar failed', message || text.slice(0, 500));
        }
        return { code: json?.media?.code };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the raw response via fetch interception/debug logging on the configure_sidecar call to see the actual body.
  2. Refresh the Instagram session cookies / re-login; a stale session is the most common cause of HTML responses.
  3. Retry after a delay; transient Instagram 5xx or rate-limiting often returns non-JSON bodies.
  4. Check the network path (proxy/VPN) is not injecting HTML into API responses.
  5. Verify the request headers built by buildPrivateApiHeaders are correct (missing headers can trigger challenge pages).

Example fix

// before
const text = await response.text();
// after
const text = await response.text();
if (/^\s*</.test(text)) throw new Error('configure_sidecar returned HTML (session expired?): ' + text.slice(0, 200));
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check session before private publish
const cookies = await page.context().cookies('https://www.instagram.com');
if (!cookies.some(c => c.name === 'ds_user_id')) throw new Error('Not logged in — configure_sidecar would return HTML');

Type guard

function isJsonObject(value) {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

Try / catch

try {
  await publishMediaViaPrivateApi({ mediaItems, apiContext });
} catch (e) {
  if (/returned invalid JSON/.test(e.message)) {
    await refreshInstagramSession(page); // HTML body usually means dead session
    await publishMediaViaPrivateApi({ mediaItems, apiContext });
  } else throw e;
}

Prevention

When it happens

Trigger: The configure_sidecar HTTP response has a non-empty body that fails JSON.parse — e.g. Instagram returned an HTML login/challenge page, a Cloudflare/proxy block page, or truncated/garbage text instead of the expected JSON envelope.

Common situations: Expired or invalid session cookies so the private API returns the login HTML page; datacenter IP blocked by Instagram returning a challenge page; corporate proxy injecting HTML; transient 5xx returning an HTML error page.

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/8a73e00a29f2ea5b. Report an issue: GitHub.