{"record":{"id":"b7be24707c8089fd","repo":"jackwener/OpenCLI","slug":"linkedin-services-read-requires-a-in-handle-pr","errorCode":null,"errorMessage":"LinkedIn services-read requires a /in/<handle>/ profile URL","messagePattern":"LinkedIn services-read requires a /in/<handle>/ profile URL","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/services-read.js","lineNumber":14,"sourceCode":"import { cli, Strategy } from '@jackwener/opencli/registry';\nimport { CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\nimport {\n  assertLinkedInAuthenticated,\n  assertSafeLinkedinUrl,\n  normalizeWhitespace,\n  unwrapEvaluateResult,\n} from './shared.js';\n\nfunction normalizeProfileUrl(value) {\n  const url = assertSafeLinkedinUrl(value || 'https://www.linkedin.com/in/me/', 'profile-url', '/in/me/');\n  const parsed = new URL(url);\n  if (!/^\\/in\\/[^/?#]+\\/?$/.test(parsed.pathname)) {\n    throw new CommandExecutionError('LinkedIn services-read requires a /in/<handle>/ profile URL');\n  }\n  return parsed.toString();\n}\n\nfunction normalizeServicesUrl(value) {\n  const url = assertSafeLinkedinUrl(value, 'services-url', '/services/page/');\n  const parsed = new URL(url);\n  if (!/^\\/services\\/page\\/[^/?#]+\\/?$/.test(parsed.pathname)) {\n    throw new CommandExecutionError('LinkedIn services-read requires a /services/page/<id>/ URL');\n  }\n  return parsed.toString();\n}\n\nfunction buildFindServicesUrlScript() {\n  return String.raw`(() => {\n    const link = Array.from(document.querySelectorAll('a[href*=\"/services/page/\"]'))\n      .map((a) => a.href || '')\n      .find(Boolean);","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/services-read.js#L1-L32","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nawait runCommand('linkedin services-read', ['--profile-url', 'https://www.linkedin.com/company/acme/']);\n// after\nawait runCommand('linkedin services-read', ['--profile-url', 'https://www.linkedin.com/in/jane-doe/']);","handlingStrategy":"validation","validationCode":"function isProfileUrl(u) {\n  try { return /^\\/in\\/[^/?#]+\\/?$/.test(new URL(u, 'https://www.linkedin.com').pathname); }\n  catch { return false; }\n}\nif (!isProfileUrl(profileUrl)) throw new Error('profile-url must be https://www.linkedin.com/in/<handle>/');","typeGuard":"function isLinkedInProfileUrl(v) {\n  try {\n    const p = new URL(String(v), 'https://www.linkedin.com');\n    return p.hostname === 'www.linkedin.com' && /^\\/in\\/[^/?#]+\\/?$/.test(p.pathname);\n  } catch { return false; }\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["linkedin","argument-validation","url"],"backgroundTag":"invalid-url-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}