{"record":{"id":"0b0c1298117d98f6","repo":"jackwener/OpenCLI","slug":"linkedin-connect-blocked-opened-reason-con","errorCode":null,"errorMessage":"LinkedIn connect blocked: ${opened?.reason || 'connect_control_not_found'}","messagePattern":"LinkedIn connect blocked: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/connect.js","lineNumber":464,"sourceCode":"            return [{ status: 'connectable_dry_run', recipient: safety.actualValue, reason: safety.blockReason, profile_url: safety.observedUrl, note_chars: note.length, connectable: true }];\n        }\n        const inviteHref = probe?.connectHref || '';\n        if (inviteHref) {\n            // Anchor-based Connect: navigate straight to the invitation route, where the\n            // \"Add a note?\" dialog renders already open.\n            const inviteUrl = canonicalizeLinkedInInviteUrl(inviteHref);\n            if (!inviteUrl) {\n                throw new CommandExecutionError('LinkedIn connect blocked: invalid_connect_link');\n            }\n            await page.goto(inviteUrl);\n            await page.wait(6);\n        }\n        else {\n            // Button-based Connect: no /preload/custom-invite/ anchor exists, so open the\n            // invite dialog in-page by clicking the Connect control (directly or via More).\n            const opened = unwrapEvaluateResult(await page.evaluate(buildOpenConnectDialogScript(expectedName)));\n            if (!opened?.ok) {\n                throw new CommandExecutionError(`LinkedIn connect blocked: ${opened?.reason || 'connect_control_not_found'}`);\n            }\n            await page.wait(3);\n        }\n        let result = unwrapEvaluateResult(await page.evaluate(buildInviteScript(note)));\n        if (result?.reason === 'invite_dialog_not_found') {\n            await page.wait(5);\n            result = unwrapEvaluateResult(await page.evaluate(buildInviteScript(note)));\n        }\n        // A button-based Connect that fired the invite without a confirmation dialog leaves\n        // no dialog to drive; treat it as sent and let the sent-invitations probe verify.\n        if (!result?.ok && result?.reason === 'invite_dialog_not_found' && !inviteHref) {\n            result = { ok: true, status: 'sent', reason: 'invitation_sent_no_dialog' };\n        }\n        if (!result?.ok) throw new CommandExecutionError(`LinkedIn connect blocked: ${result?.reason || 'send_failed'}`);\n        // LinkedIn can take a few seconds after the Send click to materialize the\n        // new invite in /mynetwork/invitation-manager/sent/. Wait before the\n        // first check, then retry page loads for propagation lag.\n        await page.wait(8);","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/connect.js#L446-L482","documentation":"Button-based Connect: when no invite anchor exists, the command runs an in-page script (buildOpenConnectDialogScript) to click the Connect control directly or via the More menu. If the script reports failure (or returns nothing), the command throws CommandExecutionError naming the script's reason, defaulting to connect_control_not_found.","triggerScenarios":"The profile has no clickable Connect button: already connected/pending invitation, profile restricts invitations (non-connectable variant that slipped past the routine check), button lives under a More menu the script did not traverse, or LinkedIn renamed/restructured the button.","commonSituations":"Target already in your network or has a pending invite; premium-only/follow-only profiles; LinkedIn A/B tests moving Connect into a different overflow menu; layout drift breaking the script's selectors.","solutions":["Confirm manually that the profile actually shows a Connect button and that you are not already connected or pending","Re-run with a fresh probe — transient render timing can hide the button; increase waits","Update the library if LinkedIn changed the Connect/More button markup","Choose a different target profile if this one genuinely does not offer Connect"],"exampleFix":"null","handlingStrategy":"retry","validationCode":"// pre-flight: skip targets already connected or pending\nconst alreadyConnected = await page.evaluate(() => !!document.querySelector('button[aria-label*=\"Pending\"], .artdeco-button--disabled'));\nif (alreadyConnected) throw new Error('Target has no Connect button (already connected/pending or restricted).');","typeGuard":"null","tryCatchPattern":"try { await runConnect(args); } catch (e) { if (String(e.message).includes('connect_control_not_found')) { await page.reload(); await runConnect(args); } else { throw e; } }","preventionTips":["Check manually that the target profile shows a Connect button before batching","Skip profiles that are already connected or have pending invites","Increase waits/retries for slow page renders","Keep the library updated for LinkedIn button/markup changes"],"tags":["linkedin","automation","dom"],"backgroundTag":"ui-element-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}