{"record":{"id":"527bee4459d44813","repo":"jackwener/OpenCLI","slug":"linkedin-job-detail-could-not-find-a-job-title","errorCode":null,"errorMessage":"LinkedIn job detail could not find a job title","messagePattern":"LinkedIn job detail could not find a job title","errorType":"error_code","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/job-detail.js","lineNumber":124,"sourceCode":"      company,\n      company_url,\n      location: locationLine,\n      workplace_type: workplaceMatch ? workplaceMatch[1] : '',\n      job_type: jobTypeMatch ? jobTypeMatch[1] : '',\n      applicants: applicantsMatch ? applicantsMatch[1] : '',\n      listed: listedMatch ? listedMatch[1] : '',\n      apply_url,\n      description,\n    };\n  })()`;\n}\n\nfunction normalizeDetail(row) {\n  if (!row || typeof row !== 'object') {\n    throw new CommandExecutionError('LinkedIn job detail returned malformed extraction payload');\n  }\n  const title = normalizeWhitespace(row.title);\n  if (!title) throw new CommandExecutionError('LinkedIn job detail could not find a job title');\n  return {\n    title,\n    company: normalizeWhitespace(row.company),\n    location: normalizeWhitespace(row.location),\n    workplace_type: normalizeWhitespace(row.workplace_type),\n    job_type: normalizeWhitespace(row.job_type),\n    applicants: normalizeWhitespace(row.applicants),\n    listed: normalizeWhitespace(row.listed),\n    apply_url: decodeLinkedinRedirect(normalizeWhitespace(row.apply_url)),\n    company_url: normalizeHttpUrl(row.company_url),\n    url: normalizeHttpUrl(row.url),\n    description: normalizeWhitespace(row.description),\n  };\n}\n\ncli({\n  site: 'linkedin',\n  name: 'job-detail',","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/job-detail.js#L106-L142","documentation":"After confirming the extraction row is an object, normalizeDetail normalizes row.title and requires a non-empty job title. If the title is missing or whitespace-only, a CommandExecutionError is thrown since title is the mandatory core of the job-detail result. The row existed, but its essential field did not.","triggerScenarios":"During `linkedin job-detail`, the extraction script returns an object whose title field is absent, null, or only whitespace — e.g. the selector matched a container that doesn't hold the job title on the current LinkedIn layout.","commonSituations":"LinkedIn A/B tests or redesign moving/renaming the title element so the extractor grabs an empty node, job cards with the title rendered only in a modal after hydration, expired jobs rendering skeleton markup with empty fields.","solutions":["Re-run; if the page was mid-hydration the title may populate on a second attempt.","Confirm the job page displays a title manually in the same browser profile; expired/rare jobs may render empty shells.","If the page shows a title but the CLI still fails, the extraction selector for title is stale — update/report the library.","As a workaround, fall back to search-results data or another field if your workflow can tolerate a degraded title source."],"exampleFix":"// before\nconst d = jobDetail(url); // CommandExecutionError: could not find a job title\n\n// after\ntry { var d = jobDetail(url); }\ncatch (e) {\n  if (e instanceof CommandExecutionError) { await sleep(3000); d = jobDetail(url); }\n  else throw e;\n}","handlingStrategy":"retry","validationCode":"await page.waitForSelector('h1, [class*=\"job-title\"], .top-card-layout__title', { timeout: 15000 });\n// only invoke once a title node exists in the DOM","typeGuard":"const hasTitle = (row) => row != null && typeof row === 'object' && typeof row.title === 'string' && row.title.trim().length > 0;","tryCatchPattern":"try {\n  return await linkedinJobDetail(jobUrl);\n} catch (e) {\n  if (e instanceof CommandExecutionError && /could not find a job title/.test(e.message)) {\n    await sleep(3000); // let SPA hydration finish\n    return linkedinJobDetail(jobUrl);\n  }\n  throw e;\n}","preventionTips":["Wait for the title element to render before extraction rather than fixed sleeps.","Re-check the posting is valid; expired jobs can render empty title shells.","If a manual check shows a title but the CLI fails, report stale title selectors for update.","Cache previously extracted titles as a fallback for known job ids."],"tags":["scraping","extraction","linkedin","missing-field"],"backgroundTag":"missing-required-field","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}