jackwener/OpenCLI · warning · EmptyResultError
No Indeed job posting found for jk "${jk}"
Error message
No Indeed job posting found for jk "${jk}" What it means
An EmptyResultError thrown when the job page loaded successfully but reports the posting as not found, or no title and no description could be extracted. It means the jk (job key) does not correspond to a live Indeed posting.
Source
Thrown at clis/indeed/job.js:72
.map(s => (s.textContent || '').trim())
.filter(t => t && t !== salary)
.join(', ');
const description = document.querySelector('#jobDescriptionText')?.innerText?.trim() ?? '';
return { ready, challenge, notFound, title, company, location, salary, jobType, description };
})()`);
}
catch (e) {
throw new CommandExecutionError(`Failed to scrape Indeed job detail DOM: ${e?.message ?? e}`, 'The page may not have fully loaded; try again.');
}
if (detail?.challenge) {
throw new CommandExecutionError('Indeed served a Cloudflare challenge page', 'Open https://www.indeed.com in the connected browser and clear the challenge, then retry.');
}
if (!detail?.ready) {
throw new CommandExecutionError('Indeed job page did not expose detail or error markers within 15s', 'Indeed may still be loading or the DOM shape may have changed; retry after opening Indeed in the connected browser.');
}
if (detail?.notFound || (!detail?.title && !detail?.description)) {
throw new EmptyResultError('indeed job', `No Indeed job posting found for jk "${jk}"`);
}
return [{
id: jk,
title: detail.title.replace(/\s+/g, ' ').trim(),
company: detail.company.replace(/\s+/g, ' ').trim(),
location: detail.location.replace(/\s+/g, ' ').trim(),
salary: detail.salary.replace(/\s+/g, ' ').trim(),
job_type: detail.jobType.replace(/\s+/g, ' ').trim(),
description: detail.description,
url,
}];
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the jk value is correct and complete (32-char job key)
- Re-obtain the jk from a fresh Indeed search — the posting may have expired
- Open the job URL directly in the connected browser to confirm it is live
- Check the posting's region/locale matches your browser session
- If you scrape many postings, refresh your source list to drop dead postings
Defensive patterns
Strategy: fallback
Validate before calling
// refresh jk values from a recent search before fetching details
const fresh = await indeed.search({ query: title, location });
if (!fresh.some(j => j.id === jk)) throw new Error(`jk ${jk} may be expired`); Try / catch
try {
const job = await indeed.job(jk);
} catch (e) {
if (e instanceof EmptyResultError || /No Indeed job posting/.test(e.message)) {
// skip this posting / fall back to a fresh search
}
throw e;
} Prevention
- Refresh job-key lists frequently; postings expire quickly
- Validate jk format before calling (32-char hex-ish key)
- Skip and log dead postings in bulk pipelines instead of failing
- Open the URL in a browser to confirm the posting is region-visible
When it happens
Trigger: detail.notFound is true, or both detail.title and detail.description are empty after a ready job page scrape for the given jk.
Common situations: Job posting was taken down/expired since you got the jk; jk copied incorrectly or truncated; posting is region-locked and renders empty for your browser's locale; Indeed removed the listing without redirecting.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- bilibili creator-stats ${bvid}
- Chess.com returned 404 for ${url}
- crates crate
- crates.io returned 404 for ${url}.
- Photo ID ${requestedPhotoId} was not found under subject ${s
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/de0b56f152b2c8a9.
Report an issue: GitHub.