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

  1. Change careers_url so the path starts with /public-api/offers/ (e.g. https://solid.jobs/public-api/offers) and keep the protocol https:
  2. If unsure of the endpoint, open the site's network tab and copy the XHR URL the offers page calls
  3. 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

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


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)