santifer/career-ops · error · Error
solidjobs: URL path must start with /public-api/offers/
Error message
solidjobs: URL path must start with /public-api/offers/: ${url} What it means
The solidjobs provider validates every careers_url before fetching, as an SSRF/allowlist guard. This specific throw fires when the URL parses, uses HTTPS, and points at solid.jobs, but its pathname does not begin with /public-api/offers/ — i.e. the configured URL is not the public offers API endpoint the provider knows how to parse.
Solutions
- Change careers_url so the path starts with /public-api/offers/ (e.g. https://solid.jobs/public-api/offers) and keep the protocol https:
- If unsure of the endpoint, open the site's network tab and copy the XHR URL the offers page calls
- Remove the entry if the provider is not actually wanted for that board
Example fix
// before careers_url: 'https://solid.jobs/offers?city=Warsaw' // after careers_url: 'https://solid.jobs/public-api/offers'
Defensive patterns
Strategy: validation
Validate before calling
const u = new URL(entry.careers_url);
if (u.protocol !== 'https:' || u.hostname !== 'solid.jobs' || !u.pathname.startsWith('/public-api/offers/')) {
throw new Error(`bad solidjobs careers_url: ${entry.careers_url}`);
} Type guard
function isValidSolidjobsUrl(u) {
try { const p = new URL(u); return p.protocol === 'https:' && p.hostname === 'solid.jobs' && p.pathname.startsWith('/public-api/offers/'); }
catch { return false; }
} Try / catch
try {
await provider.fetch(entry, ctx);
} catch (e) {
if (String(e.message).includes('URL path must start with /public-api/offers/')) {
console.warn(`Skipping ${entry.name}: careers_url is not the offers API endpoint`);
return [];
}
throw e;
} Prevention
- Always configure the /public-api/offers/ endpoint, not the website URL
- Validate portals.yml entries with verify-pipeline.mjs after edits
- Keep a canonical example entry per provider in a template
When it happens
Trigger: A portals.yml entry with provider solidjobs has a careers_url pointing at a website page (e.g. https://solid.jobs/en or https://solid.jobs/offers/123) instead of the API path /public-api/offers/...; or someone pastes a shareable job link rather than the API URL.
Common situations: Copying the browser URL from a solid.jobs listing page instead of the API endpoint; a solid.jobs URL-shape change or a hand-edited config adding a query/path prefix; typo'd base URL in a template.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- himalayas: untrusted hostname
- itviec: untrusted hostname
- jobbankca: invalid URL
- jobspresso: invalid URL
- jobstreet: invalid URL
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/78c79debaecc8d01.
Report an issue: GitHub.
Appendix: source
Thrown at providers/solidjobs.mjs:31
* Validates that the provided URL is a trusted SolidJobs API endpoint.
* Enforces HTTPS protocol, strict hostname matching, and required path prefix.
*
* @param {string} url - The URL string to validate.
* @returns {string} The validated URL string.
* @throws {Error} If the URL is malformed, uses non-HTTPS, has an untrusted host, or wrong path.
*/
function assertUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`solidjobs: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`solidjobs: URL must use HTTPS: ${url}`);
if (!ALLOWED_HOSTS.has(parsed.hostname))
throw new Error(`solidjobs: untrusted hostname "${parsed.hostname}" — must be solid.jobs`);
if (!parsed.pathname.startsWith('/public-api/offers/'))
throw new Error(`solidjobs: URL path must start with /public-api/offers/: ${url}`);
return url;
}
/** @type {Provider} */
export default {
id: 'solidjobs',
/**
* Attempts to detect if the provider can handle the given entry by checking the careers_url.
* * @param {{ careers_url?: string, name?: string }} entry - The configuration entry.
* @returns {{url: string} | null} An object with the matched URL, or null if not matched.
*/
detect(entry) {
const url = entry.careers_url || '';
try {
const parsed = new URL(url);
if (parsed.hostname === 'solid.jobs' && parsed.pathname.startsWith('/public-api/offers/'))
return { url };View on GitHub (pinned to aac998c7ed)