jackwener/OpenCLI · error · CommandExecutionError

LinkedIn thread-snapshot blocked: thread_url_mismatch

Error message

LinkedIn thread-snapshot blocked: thread_url_mismatch

What it means

The linkedin thread-snapshot command opens the given messaging thread URL and extracts the URL the browser actually landed on via an in-page discovery script. If both the requested and discovered URLs are present and canonicalize to different threads, the command refuses to snapshot the wrong conversation and throws this CommandExecutionError.

Source

Thrown at clis/linkedin/thread-snapshot.js:344

        discovery = {
          ...retried,
          scrollAttempts: firstDiscovery.scrollAttempts,
          scrollStable: firstDiscovery.scrollStable,
        };
      } else {
        discovery = retried;
      }
    }
    if (discovery?.authRequired) {
      throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn thread-snapshot requires an active signed-in LinkedIn browser session.');
    }
    if (!discovery || typeof discovery !== 'object' || Array.isArray(discovery) || !Array.isArray(discovery.apiUrls)) {
      throw new CommandExecutionError('LinkedIn thread-snapshot returned a malformed API discovery payload.');
    }

    const actualUrl = canonicalizeLinkedInThreadUrl(discovery.url || '');
    if (threadUrl && actualUrl && threadUrl !== actualUrl) {
      throw new CommandExecutionError('LinkedIn thread-snapshot blocked: thread_url_mismatch', `Expected ${threadUrl}; actual ${actualUrl}`);
    }
    if (maxScrolls >= 4 && discovery.scrollAttempts >= maxScrolls && discovery.scrollStable === false) {
      throw new CommandExecutionError('LinkedIn thread history did not stabilize before --max-scrolls; refusing to return a partial snapshot.');
    }

    const apiUrls = validateThreadApiUrls(discovery.apiUrls, threadUrl);
    const csrf = await requireLinkedInCookie(page, 'LinkedIn thread-snapshot');
    const fetched = unwrapEvaluateResult(
      await page.evaluate(buildFetchThreadPagesScript(apiUrls, csrf)),
    );
    if (fetched?.authRequired) {
      throw new AuthRequiredError(LINKEDIN_DOMAIN, `LinkedIn messengerMessages API authentication failed: ${fetched.error}`);
    }
    if (!fetched || fetched.error || !Array.isArray(fetched.pages)) {
      throw new CommandExecutionError(`LinkedIn messengerMessages API returned an unexpected response: ${fetched?.error || 'no data'}`);
    }

    const parsed = parseThreadPages(fetched.pages);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-open LinkedIn Messaging in the browser, click the intended thread, and copy the exact URL from the address bar
  2. Canonicalize the URL the same way the CLI does (strip query params/fragments) and compare before invoking
  3. Check whether the original thread was deleted or archived and re-run with the new thread URL

Example fix

// before
linkedin thread-snapshot --thread-url 'https://www.linkedin.com/messaging/thread/old-id/'
// after
linkedin thread-snapshot --thread-url 'https://www.linkedin.com/messaging/thread/current-id/'
Defensive patterns

Strategy: validation

Validate before calling

const canon = u => u.split('?')[0].split('#')[0].replace(/\/$/,'');
if (canon(requestedUrl) !== canon(actualThreadUrl)) throw new Error('thread URL mismatch before calling thread-snapshot');

Type guard

const isSameThread = (a, b) => !!a && !!b && a.split('?')[0].replace(/\/$/,'') === b.split('?')[0].replace(/\/$/,'');

Try / catch

try {
  await threadSnapshot({ threadUrl });
} catch (e) {
  if (String(e.message).includes('thread_url_mismatch')) {
    // re-copy the URL from the browser and retry once
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `linkedin thread-snapshot --thread-url <url>` where the page's discovered thread URL (discovery.url) canonicalizes to a different thread than the requested threadUrl — typically when the thread was deleted, redirected, or the URL was typo'd/copied stale.

Common situations: Reusing an old thread URL after LinkedIn redirected the conversation; pasting a share link instead of the messenger thread URL; copy-paste errors truncating or altering the thread ID; LinkedIn redirecting to a different conversation after archiving/deleting the original.

Related errors


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