jackwener/OpenCLI · error · CommandExecutionError
LinkedIn services-read requires a /in/<handle>/ profile URL
Error message
LinkedIn services-read requires a /in/<handle>/ profile URL
What it means
normalizeProfileUrl validates the --profile-url argument for linkedin services-read. After assertSafeLinkedinUrl confirms it is a safe linkedin.com URL, the pathname must match /in/<handle>/. Anything else (company pages, feed URLs, posts) is rejected with this ArgumentError because Services discovery only works on personal profile pages.
Source
Thrown at clis/linkedin/services-read.js:14
import { cli, Strategy } from '@jackwener/opencli/registry';
import { CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';
import {
assertLinkedInAuthenticated,
assertSafeLinkedinUrl,
normalizeWhitespace,
unwrapEvaluateResult,
} from './shared.js';
function normalizeProfileUrl(value) {
const url = assertSafeLinkedinUrl(value || 'https://www.linkedin.com/in/me/', 'profile-url', '/in/me/');
const parsed = new URL(url);
if (!/^\/in\/[^/?#]+\/?$/.test(parsed.pathname)) {
throw new CommandExecutionError('LinkedIn services-read requires a /in/<handle>/ profile URL');
}
return parsed.toString();
}
function normalizeServicesUrl(value) {
const url = assertSafeLinkedinUrl(value, 'services-url', '/services/page/');
const parsed = new URL(url);
if (!/^\/services\/page\/[^/?#]+\/?$/.test(parsed.pathname)) {
throw new CommandExecutionError('LinkedIn services-read requires a /services/page/<id>/ URL');
}
return parsed.toString();
}
function buildFindServicesUrlScript() {
return String.raw`(() => {
const link = Array.from(document.querySelectorAll('a[href*="/services/page/"]'))
.map((a) => a.href || '')
.find(Boolean);View on GitHub (pinned to 49907e53dc)
Solutions
- Pass a personal profile URL of the form https://www.linkedin.com/in/<handle>/ to --profile-url.
- If you only have a company page, use --services-url with the /services/page/<id>/ URL directly instead.
- Omit --profile-url entirely so the command defaults to /in/me/ (the logged-in profile).
Example fix
// before
await runCommand('linkedin services-read', ['--profile-url', 'https://www.linkedin.com/company/acme/']);
// after
await runCommand('linkedin services-read', ['--profile-url', 'https://www.linkedin.com/in/jane-doe/']); Defensive patterns
Strategy: validation
Validate before calling
function isProfileUrl(u) {
try { return /^\/in\/[^/?#]+\/?$/.test(new URL(u, 'https://www.linkedin.com').pathname); }
catch { return false; }
}
if (!isProfileUrl(profileUrl)) throw new Error('profile-url must be https://www.linkedin.com/in/<handle>/'); Type guard
function isLinkedInProfileUrl(v) {
try {
const p = new URL(String(v), 'https://www.linkedin.com');
return p.hostname === 'www.linkedin.com' && /^\/in\/[^/?#]+\/?$/.test(p.pathname);
} catch { return false; }
} Prevention
- Always build profile URLs from a handle: `https://www.linkedin.com/in/${handle}/`.
- Distinguish company pages from personal profiles before passing them.
- Omit --profile-url to use the default /in/me/ when you mean the logged-in user.
When it happens
Trigger: Passing --profile-url that is not a /in/<handle>/ path, e.g. https://www.linkedin.com/company/foo/, https://www.linkedin.com/feed/, a bare handle like 'john-doe', or a /in/ URL with an empty handle.
Common situations: Copy-pasting a company page or a public post URL instead of the personal profile; passing a vanity name without the /in/ prefix; trailing query strings are fine but a /in/ path without a handle is not.
Related errors
- job-url must be a https://www.linkedin.com/jobs/view/<id> UR
- Sales Navigator lead URL must contain resolved profileId, au
- LinkedIn services-read requires a /services/page/<id>/ URL
- ${label} must be a LinkedIn URL
- ${label} must be an https LinkedIn URL without credentials o
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/b7be24707c8089fd.
Report an issue: GitHub.