{"record":{"id":"78c79debaecc8d01","repo":"santifer/career-ops","slug":"solidjobs-url-path-must-start-with-public-api-of","errorCode":null,"errorMessage":"solidjobs: URL path must start with /public-api/offers/: ${url}","messagePattern":"solidjobs: URL path must start with /public-api/offers/: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/solidjobs.mjs","lineNumber":31,"sourceCode":" * Validates that the provided URL is a trusted SolidJobs API endpoint.\n * Enforces HTTPS protocol, strict hostname matching, and required path prefix.\n * \n * @param {string} url - The URL string to validate.\n * @returns {string} The validated URL string.\n * @throws {Error} If the URL is malformed, uses non-HTTPS, has an untrusted host, or wrong path.\n */\nfunction assertUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`solidjobs: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`solidjobs: URL must use HTTPS: ${url}`);\n  if (!ALLOWED_HOSTS.has(parsed.hostname))\n    throw new Error(`solidjobs: untrusted hostname \"${parsed.hostname}\" — must be solid.jobs`);\n  if (!parsed.pathname.startsWith('/public-api/offers/'))\n    throw new Error(`solidjobs: URL path must start with /public-api/offers/: ${url}`);\n  return url;\n}\n\n/** @type {Provider} */\nexport default {\n  id: 'solidjobs',\n\n  /**\n   * Attempts to detect if the provider can handle the given entry by checking the careers_url.\n   * * @param {{ careers_url?: string, name?: string }} entry - The configuration entry.\n   * @returns {{url: string} | null} An object with the matched URL, or null if not matched.\n   */\n  detect(entry) {\n    const url = entry.careers_url || '';\n    try {\n      const parsed = new URL(url);\n      if (parsed.hostname === 'solid.jobs' && parsed.pathname.startsWith('/public-api/offers/'))\n        return { url };","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/providers/solidjobs.mjs#L13-L49","documentation":"assertUrl's final check requires parsed.pathname to start with '/public-api/offers/'. It fires after parse, https, and host all pass — so the URL is a valid https://solid.jobs URL but points somewhere other than the public offers API (e.g. the marketing landing page, a division listing without the prefix, or the root).","triggerScenarios":"entry.careers_url is https://solid.jobs or https://solid.jobs/it rather than https://solid.jobs/public-api/offers/<division>. The API lives under /public-api/offers/ only.","commonSituations":"The user pasted the browsable careers landing page instead of the API endpoint. Valid divisions are: it, engineering, marketing, sales, hr, logistics, finances, other (per the module header).","solutions":["Append the API path and a division: https://solid.jobs/public-api/offers/it","Pick the correct division from the supported list (it, engineering, marketing, sales, hr, logistics, finances, other)","Optionally add ?campaign=<campaign> if the API docs require one"],"exampleFix":"# before\ncareers_url: https://solid.jobs\n# after\ncareers_url: https://solid.jobs/public-api/offers/it","handlingStrategy":"validation","validationCode":"// Ensure the API path prefix is present.\nfunction hasOffersPath(v) {\n  try { return new URL(v).pathname.startsWith('/public-api/offers/'); } catch { return false; }\n}\nif (!hasOffersPath(entry.careers_url)) {\n  console.warn(`${entry.name}: solidjobs URL must include /public-api/offers/<division>`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Store the API endpoint, not the browsable landing page.","Pick a valid division (it/engineering/marketing/sales/hr/logistics/finances/other)."],"tags":["url-validation","api-endpoint","config","solidjobs","portals-yml"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}