{"record":{"id":"bd44a2f675a734c2","repo":"jackwener/OpenCLI","slug":"returned-malformed-post-row-bd44a2","errorCode":null,"errorMessage":" returned malformed post row","messagePattern":" returned malformed post row","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"clis/instagram/save.js","lineNumber":41,"sourceCode":"  if (!Number.isInteger(idx) || idx < 0) throw new Error('index must be a positive integer');\n  const headers = { 'X-IG-App-ID': '936619743392459' };\n  const opts = { credentials: 'include', headers };\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 getPostFromFeed(feed, label) {\n    if (!feed || typeof feed !== 'object' || !Array.isArray(feed.items)) {\n      throw new Error(label + ' returned malformed items payload');\n    }\n    if (idx >= feed.items.length) throw new Error('Post index ' + (idx + 1) + ' not found');\n    const post = feed.items[idx];\n    const pkRaw = post?.pk ?? post?.id;\n    const pk = typeof pkRaw === 'number' ? String(pkRaw) : (typeof pkRaw === 'string' ? pkRaw.trim() : '');\n    if (!/^\\\\d+$/.test(pk)) throw new Error(label + ' returned malformed post row');\n    const caption = typeof post?.caption?.text === 'string' ? post.caption.text.substring(0, 60) : '';\n    return { pk, caption };\n  }\n  function assertOkStatus(payload, label) {\n    if (!payload || typeof payload !== 'object' || payload.status !== 'ok') {\n      throw new Error(label + ' returned no success evidence');\n    }\n  }\n\n  // web_profile_info answers HTTP 400 for business accounts; feed-by-username needs no user id. See #2234.\n  const r1 = await fetch('https://www.instagram.com/api/v1/feed/user/' + encodeURIComponent(username) + '/username/?count=' + (idx + 1), opts);\n  if (!r1.ok) throw new Error(r1.status === 404 ? 'User not found: ' + username : 'HTTP ' + r1.status + ' - make sure you are logged in to Instagram');\n  const { pk, caption } = getPostFromFeed(await readInstagramJson(r1, 'Instagram feed-by-username'), 'Instagram feed-by-username');\n\n  const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';\n  const r2 = await fetch('https://www.instagram.com/api/v1/web/save/' + pk + '/save/', {\n    method: 'POST', credentials: 'include',\n    headers: { ...headers, 'X-CSRFToken': csrf, 'Content-Type': 'application/x-www-form-urlencoded' },","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/instagram/save.js#L23-L59","documentation":"Thrown by `getPostFromFeed` when the selected feed item has no usable post identifier: `post.pk ?? post.id` is missing, or its string form does not match /^\\d+$/. The media `pk` is required to build the save URL (/api/v1/web/save/<pk>/save/), so a row without a numeric pk cannot be saved.","triggerScenarios":"feed.items[idx] is a non-media object (ad, banner, story tray entry, or `clip`/`awaiting` wrapper) lacking `pk`/`id`, or the id is a non-numeric string, so the pk regex test fails.","commonSituations":"Instagram injects ads or suggested-post entries into user feeds; carousel/story placeholder rows appear in items; the target post is a reel/clip wrapped in an envelope where pk lives at a nested path; an Instagram schema change renames the id field.","solutions":["Try a different --index value — the row at that position may be an ad or non-media entry without a pk.","Dump the item's JSON (or check in DevTools on instagram.com) to find where the numeric pk actually sits in the current schema.","Update the CLI's pk extraction if Instagram changed the field layout (e.g. nested item.media.pk).","Save the post manually on the web if the feed keeps returning rows without identifiers."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function hasNumericPk(post) {\n  const raw = post?.pk ?? post?.id;\n  return (typeof raw === 'number' && Number.isFinite(raw)) ||\n         (typeof raw === 'string' && /^\\d+$/.test(raw.trim()));\n}","tryCatchPattern":"try {\n  await run(['instagram', 'save', username, '--index', String(i)]);\n} catch (e) {\n  if (String(e.message).includes('returned malformed post row')) {\n    // feed row has no usable pk (ad/placeholder) — try the next index\n    return run(['instagram', 'save', username, '--index', String(i + 1)]);\n  }\n  throw e;\n}","preventionTips":["If a given index fails, try a neighboring index — ads/placeholders occupy feed rows.","Update the CLI when Instagram changes where pk/id lives in feed items.","Prefer saving via a post URL when feed rows repeatedly lack identifiers."],"tags":["schema-validation","instagram","data-integrity"],"backgroundTag":"missing-identifier-field","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}