jackwener/OpenCLI · error

' + label + ' returned malformed post row

Error message

' + label + ' returned malformed post row

What it means

The matched feed item did not contain a usable post id: neither pk nor id was present, or the value failed the /^\d+$/ numeric-string check. The CLI cannot build the unsave URL without a valid post primary key.

Source

Thrown at clis/instagram/unsave.js:41

  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');
    }
  }

  // web_profile_info answers HTTP 400 for business accounts; feed-by-username needs no user id. See #2234.
  const r1 = await fetch('https://www.instagram.com/api/v1/feed/user/' + encodeURIComponent(username) + '/username/?count=' + (idx + 1), opts);
  if (!r1.ok) throw new Error(r1.status === 404 ? 'User not found: ' + username : 'HTTP ' + r1.status + ' - make sure you are logged in to Instagram');
  const { pk, caption } = getPostFromFeed(await readInstagramJson(r1, 'Instagram feed-by-username'), 'Instagram feed-by-username');

  const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] || '';
  const r2 = await fetch('https://www.instagram.com/api/v1/web/save/' + pk + '/unsave/', {
    method: 'POST', credentials: 'include',
    headers: { ...headers, 'X-CSRFToken': csrf, 'Content-Type': 'application/x-www-form-urlencoded' },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Try a different --index pointing at a normal post.
  2. Inspect the feed item to find where the id now lives and update the CLI.
  3. Skip ads/stories rows when computing the index.
Defensive patterns

Strategy: type-guard

Validate before calling

const hasPk = (post) => /^\d+$/.test(String(post?.pk ?? post?.id ?? ''));

Type guard

function hasValidPostId(post) {
  const pk = post?.pk ?? post?.id;
  return typeof pk !== 'undefined' && /^\d+$/.test(String(pk));
}

Prevention

When it happens

Trigger: feed item is an ad, story, or non-media row lacking pk/id, or Instagram returns a different id field for that media type.

Common situations: Targeting an index that points to a promoted/ad item in the feed; new Instagram media types with different id shapes; API shape drift.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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