jackwener/OpenCLI · error · CommandExecutionError

LinkedIn sent invitations contained a malformed invitation c

Error message

LinkedIn sent invitations contained a malformed invitation card.

What it means

Card candidates that have both a profile link and a Withdraw action but yield no parseable name or profile URL are counted in malformedCount. The command treats any malformed card as a hard failure (no silent partial data for CRM reconciliation) and throws this CommandExecutionError listing nothing but signaling the DOM produced an unparseable invitation card.

Source

Thrown at clis/linkedin/sent-invitations.js:105

  browser: true,
  args: [],
  columns: ['rank', 'name', 'profile_url', 'invited_date_text'],
  func: async (page) => {
    if (!page) throw new CommandExecutionError('Browser session required for linkedin sent-invitations');
    await page.goto(SENT_URL);
    await page.wait(12);
    let result = unwrapEvaluateResult(await page.evaluate(buildSentInvitationsScript()));
    if (result?.authRequired) {
      throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn sent invitations requires an active signed-in browser session.');
    }
    if (result?.warning) {
      throw new CommandExecutionError('LinkedIn warning/restriction state visible on sent invitations page.');
    }
    if (!result || typeof result !== 'object' || Array.isArray(result) || !Array.isArray(result.rows)) {
      throw new CommandExecutionError('LinkedIn sent invitations returned a malformed extraction payload.');
    }
    if (result.malformedCount > 0) {
      throw new CommandExecutionError('LinkedIn sent invitations contained a malformed invitation card.');
    }
    const rows = result.rows;
    if (rows.length === 0) {
      if (result.explicitEmpty) {
        throw new EmptyResultError('linkedin sent-invitations', 'No pending sent invitations were found.');
      }
      throw new CommandExecutionError('LinkedIn sent invitation cards were not found; the page structure may have changed.');
    }
    return rows.map((row, index) => ({
      rank: index + 1,
      name: row.name || '',
      profile_url: row.profile_url || '',
      invited_date_text: row.invited_date_text || '',
    }));
  },
});

export const __test__ = {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the invitation-manager page in the browser to see which card fails to parse; if a member was deleted/deactivated, that card may be inherently empty — consider handling it upstream in the extraction script.
  2. Update the extraction selectors/regexes in buildSentInvitationsScript to match the current LinkedIn card markup and aria-label patterns.
  3. Disable browser extensions in the automation profile and retry with the UI language set to English so the /^withdraw/i and date regexes match.
  4. Clear the checkpoint by reloading the page; if only transient rendering caused it, a re-run after a full load (increase the 12s wait) may parse all cards.

Example fix

// before (strict fail on any malformed card)
if (result.malformedCount > 0) throw new CommandExecutionError('...malformed invitation card.');
// after (tolerate known-empty cards for deleted members)
if (result.malformedCount > 0) {
  console.error(`[linkedin] skipped ${result.malformedCount} unparseable card(s)`);
  // or: filter candidate cards lacking a[href*="/in/"] before counting
}
Defensive patterns

Strategy: fallback

Validate before calling

null

Type guard

const isWellFormedCard = (card) => {
  const link = card?.querySelector?.('a[href*="/in/"]');
  const name = link?.innerText || link?.textContent || link?.getAttribute('aria-label') || '';
  return Boolean(name.trim()) && Boolean(link?.getAttribute('href'));
};

Try / catch

try {
  const rows = await run(['linkedin', 'sent-invitations']);
} catch (e) {
  if (/malformed invitation card/.test(e.message)) {
    console.warn('LinkedIn card markup not fully parseable; falling back to manual export of the invitation manager page.');
    // Fall back to a manual/CSV flow instead of failing the CRM sync
    return manualInvitationExport();
  }
  throw e;
}

Prevention

When it happens

Trigger: Running `opencli linkedin sent-invitations` when at least one invitation card on the page fails parsing: no name derivable from the withdraw aria-label, profile link text, or card lines; or the /in/ link's href is empty — i.e. LinkedIn renders a card variant the extractors do not recognize.

Common situations: LinkedIn UI update changing invitation card markup (new layout, renamed aria-labels); a card for a deleted/deactivated member rendering with missing name/href; localized UI text breaking the /^withdraw .../i and 'Sent X days ago' regexes; injected browser extensions altering the DOM.

Understand the failure class

Related errors


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