jackwener/OpenCLI · error · CommandExecutionError

LinkedIn connect blocked: ${safety.blockReason}

Error message

LinkedIn connect blocked: ${safety.blockReason}

What it means

assessProfileSafety compares the observed profile against the expected name and connectability. If safety checks fail for any reason other than auth or routine non-connectability (e.g. wrong profile, page did not render, unexpected URL), the command throws CommandExecutionError with the safety blockReason as the message and diagnostic details (expected vs actual name, observed URL, visible buttons) as secondary info.

Source

Thrown at clis/linkedin/connect.js:440

        // The name resolves early (from document.title), but the profile action
        // buttons (Connect / Message / Pending) render later. Keep probing until
        // the action state has resolved, not merely until the name is visible.
        for (let attempt = 0; attempt < 8; attempt += 1) {
            const resolved = probe?.name
                && (probe.connectAvailable || probe.alreadyConnected || probe.pending || probe.moreAvailable);
            if (resolved) break;
            await page.wait(2);
            probe = await probeProfile(page, expectedName);
        }
        const safety = assessProfileSafety(probe, expectedName, profileUrl);
        if (safety.blockReason === 'auth_required') {
            throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn connect requires an active signed-in LinkedIn browser session.');
        }
        if (!safety.ok && safety.safety === 'routine_non_connectable') {
            return [{ status: 'not_connectable', recipient: safety.actualValue, reason: safety.blockReason, profile_url: safety.observedUrl, note_chars: note.length, connectable: false }];
        }
        if (!safety.ok) {
            throw new CommandExecutionError(
                `LinkedIn connect blocked: ${safety.blockReason}`,
                `Expected ${safety.expectedValue}; actual ${safety.actualValue || 'not_visible'} at ${safety.observedUrl || 'url_not_available'}\nButtons: ${(probe?.buttonLabels || []).join(' | ')}`,
            );
        }
        if (!args.send) {
            return [{ status: 'connectable_dry_run', recipient: safety.actualValue, reason: safety.blockReason, profile_url: safety.observedUrl, note_chars: note.length, connectable: true }];
        }
        const inviteHref = probe?.connectHref || '';
        if (inviteHref) {
            // Anchor-based Connect: navigate straight to the invitation route, where the
            // "Add a note?" dialog renders already open.
            const inviteUrl = canonicalizeLinkedInInviteUrl(inviteHref);
            if (!inviteUrl) {
                throw new CommandExecutionError('LinkedIn connect blocked: invalid_connect_link');
            }
            await page.goto(inviteUrl);
            await page.wait(6);
        }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify --expected-name matches the profile's current display name exactly (or relax expected-name if the library allows)
  2. Load the profile URL manually in a browser to confirm it still exists and shows the expected person
  3. Increase patience/retry waits if the page is slow, then re-run
  4. Update the library if LinkedIn layout drift is breaking probeProfile's selectors

Example fix

// before
--profile-url "https://www.linkedin.com/in/jane-doe/" --expected-name "Janet Doe"
// after
--profile-url "https://www.linkedin.com/in/jane-doe/" --expected-name "Jane Doe"
Defensive patterns

Strategy: try-catch

Validate before calling

const expected = (args['expected-name'] || '').trim();
if (!expected) throw new Error('--expected-name must match the profile display name exactly');
// optionally pre-fetch the page and confirm the h1 matches expected before automation

Type guard

null

Try / catch

try { await runConnect(args); } catch (e) { if (String(e.message).startsWith('LinkedIn connect blocked:')) { console.error(e.message, e.secondary || ''); /* inspect expected/actual diagnostics */ } else { throw e; } }

Prevention

When it happens

Trigger: The loaded page's visible name does not match --expected-name; the profile URL redirected elsewhere; the profile page failed to render its identity elements; probe returned no recognizable profile structure.

Common situations: Typos or stale --expected-name vs a renamed profile; profile deleted/private/redirected; LinkedIn layout drift breaking the probe; slow load leaving the probe to read an intermediate page.

Related errors


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