{"record":{"id":"f0adf71a3dca7ecf","repo":"santifer/career-ops","slug":"solidjobs-invalid-url-url","errorCode":null,"errorMessage":"solidjobs: invalid URL: ${url}","messagePattern":"solidjobs: invalid URL: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"providers/solidjobs.mjs","lineNumber":25,"sourceCode":"// Available divisions: it, engineering, marketing, sales, hr, logistics, finances, other\n// API docs: https://solid.jobs/public-api/offers/{division}?campaign={campaign}\n\nconst ALLOWED_HOSTS = new Set(['solid.jobs']);\n\n/**\n * 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   */","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/solidjobs.mjs#L7-L43","documentation":"assertUrl in providers/solidjobs.mjs throws this when the URL cannot be parsed by the URL constructor — it is not a syntactically valid absolute URL. The provider validates entry.careers_url before fetching, so a malformed URL is rejected with this explicit message instead of a generic fetch failure.","triggerScenarios":"A solidjobs portals entry whose careers_url is missing the scheme ('solid.jobs/public-api/offers/it'), contains spaces or invalid characters, or is empty/undefined stringified; calling assertUrl directly with user input that isn't a URL.","commonSituations":"Hand-edited portals.yml missing https://; placeholder text never replaced; trailing whitespace or newline pasted into the config value; yml quoting issues that mangle the value.","solutions":["Add the missing scheme — use https://solid.jobs/public-api/offers/<division>","Trim whitespace/newlines from the configured careers_url value","Check YAML quoting so the full URL lands in one string value","Use one of the documented division slugs (it, engineering, marketing, sales, hr, logistics, finances, other) so the path segment is valid"],"exampleFix":"// before\ncareers_url: 'solid.jobs/public-api/offers/it'  // no scheme\n// after\ncareers_url: 'https://solid.jobs/public-api/offers/it'","handlingStrategy":"validation","validationCode":"function isValidSolidjobsUrl(url) {\n  try { new URL(url); return true; } catch { return false; }\n}\nif (entry.provider === 'solidjobs' && !isValidSolidjobsUrl(entry.careers_url)) {\n  throw new Error(`solidjobs careers_url is not a valid URL: ${entry.careers_url}`);\n}","typeGuard":"const isParseableUrl = (v) => {\n  if (typeof v !== 'string') return false;\n  try { new URL(v); return true; } catch { return false; }\n};","tryCatchPattern":"try {\n  await solidjobsProvider.fetch(entry, ctx);\n} catch (e) {\n  if (String(e.message).includes('invalid URL')) {\n    console.error(`Entry ${entry.name}: careers_url is malformed — needs absolute https://solid.jobs/... form`);\n  } else throw e;\n}","preventionTips":["Always write absolute URLs with the https:// scheme in portals.yml","Trim pasted values — stray whitespace or newlines break URL parsing","Validate every careers_url with new URL() at config load time","Quote YAML values containing special characters so they stay single strings"],"tags":["url-validation","url-parse","config-error"],"backgroundTag":"invalid-url-format","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}