{"record":{"id":"d540e979724c0a3e","repo":"jackwener/OpenCLI","slug":"label-returned-invalid-json","errorCode":null,"errorMessage":"${label} returned invalid JSON","messagePattern":"(.+?) returned invalid JSON","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clis/instagram/_shared/user-id.js","lineNumber":20,"sourceCode":" * In-page snippet that resolves `username` to a numeric user id in `userId`.\n *\n * `web_profile_info` answers HTTP 400 for business and professional accounts,\n * so the commands that need an id fall back to feed-by-username. Its root\n * `user.pk` is the profile owner; `items[0].user.pk` can be a pinned collab\n * author. Callers must already have `username` and `opts` in scope.\n */\nexport function buildResolveInstagramUserIdJs() {\n    return `\n  function normalizeInstagramUserId(value, label) {\n    const id = typeof value === 'number' ? String(value) : (typeof value === 'string' ? value.trim() : '');\n    if (!/^\\\\d+$/.test(id)) throw new Error(label);\n    return id;\n  }\n  async function readInstagramJson(response, label) {\n    try {\n      return await response.json();\n    } catch {\n      throw new Error(label + ' returned invalid JSON');\n    }\n  }\n  function throwInstagramHttpError(response, label, username) {\n    if (response.status === 404) throw new Error('User not found: ' + username);\n    if (response.status === 401 || response.status === 403) {\n      throw new Error('HTTP ' + response.status + ' - make sure you are logged in to Instagram');\n    }\n    throw new Error(label + ' failed: HTTP ' + response.status);\n  }\n  const r1 = await fetch('https://www.instagram.com/api/v1/users/web_profile_info/?username=' + encodeURIComponent(username), opts);\n  if (r1.status === 404) throw new Error('User not found: ' + username);\n  if (!r1.ok && r1.status !== 400) throwInstagramHttpError(r1, 'Instagram web_profile_info', username);\n  let userId = r1.ok ? normalizeInstagramUserId((await readInstagramJson(r1, 'Instagram web_profile_info'))?.data?.user?.id, 'Instagram web_profile_info returned no valid user id for: ' + username) : '';\n  if (!userId) {\n    const r1b = await fetch('https://www.instagram.com/api/v1/feed/user/' + encodeURIComponent(username) + '/username/?count=1', opts);\n    if (!r1b.ok) throwInstagramHttpError(r1b, 'Instagram feed-by-username', username);\n    userId = normalizeInstagramUserId((await readInstagramJson(r1b, 'Instagram feed-by-username'))?.user?.pk, 'Instagram feed returned no valid profile owner for: ' + username);\n  }`;","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/instagram/_shared/user-id.js#L2-L38","documentation":"readInstagramJson in the in-page resolver wraps response.json(); if the body is not valid JSON it throws '<label> returned invalid JSON'. This surfaces when Instagram's web_profile_info or feed-by-username endpoints return non-JSON bodies (HTML login/challenge pages, empty or truncated bodies) with an HTTP status that passed the earlier ok checks.","triggerScenarios":"response.json() rejects inside readInstagramJson for either fetch — typically because the body is HTML (login redirect, challenge page) or empty despite an otherwise acceptable HTTP status.","commonSituations":"Expired session cookies so Instagram serves the login HTML page with 200; IP rate-limited with an HTML interstitial; proxy truncating the body; content-type changed by Instagram.","solutions":["Re-login / refresh session cookies — HTML responses at 200 almost always mean the session is gone.","Log response status and the first bytes of the body to confirm an HTML challenge page.","Retry after backoff if it is a transient rate-limit interstitial.","Change IP / use a residential proxy if Instagram is challenge-blocking the current IP.","Ensure request opts include proper headers/credentials so the API returns JSON."],"exampleFix":"// before\nconst userId = await page.evaluate(buildResolveInstagramUserIdJs());\n// after\ntry {\n  return await page.evaluate(buildResolveInstagramUserIdJs());\n} catch (e) {\n  if (String(e.message).includes('returned invalid JSON')) {\n    await refreshInstagramSession(page);\n    return page.evaluate(buildResolveInstagramUserIdJs());\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"const cookies = await page.context().cookies('https://www.instagram.com');\nif (!cookies.some(c => c.name === 'sessionid')) throw new Error('Session expired — user-id resolution would get HTML');","typeGuard":"function looksLikeJson(text) {\n  return /^\\s*[{[]/.test(text);\n}","tryCatchPattern":"try {\n  return await page.evaluate(buildResolveInstagramUserIdJs());\n} catch (e) {\n  if (String(e.message).includes('returned invalid JSON')) {\n    await refreshInstagramSession(page);\n    return page.evaluate(buildResolveInstagramUserIdJs()); // retry once\n  }\n  throw e;\n}","preventionTips":["Keep the browser session logged in; HTML-at-200 means login is required.","Avoid heavily rate-limited IPs; Instagram serves interstitials there.","Sniff response content when debugging to detect HTML vs JSON.","Retry once after session refresh before giving up."],"tags":["instagram","json-parse","session","http-response"],"backgroundTag":"invalid-json-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}