{"record":{"id":"d5558b9ac288e506","repo":"santifer/career-ops","slug":"getonbrd-invalid-url-url","errorCode":null,"errorMessage":"getonbrd: invalid URL: ${url}","messagePattern":"getonbrd: invalid URL: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"providers/getonbrd.mjs","lineNumber":81,"sourceCode":"  }\n  if (!out.length) {\n    throw new Error('getonbrd: `categories` is empty — omit it to use the \"programming\" default');\n  }\n  if (out.length > MAX_CATEGORIES) {\n    throw new Error(\n      `getonbrd: ${out.length} categories configured — cap is ${MAX_CATEGORIES} (each one costs up to max_pages requests)`,\n    );\n  }\n  return out;\n}\n\n/** @param {string} url */\nfunction assertGetonbrdUrl(url) {\n  let parsed;\n  try {\n    parsed = new URL(url);\n  } catch {\n    throw new Error(`getonbrd: invalid URL: ${url}`);\n  }\n  if (parsed.protocol !== 'https:') throw new Error(`getonbrd: URL must use HTTPS: ${url}`);\n  if (parsed.hostname !== TRUSTED_HOST) {\n    throw new Error(`getonbrd: untrusted hostname \"${parsed.hostname}\" — must be ${TRUSTED_HOST}`);\n  }\n  return url;\n}\n\n/** Resolve the page cap: a positive integer `max_pages` on the entry, capped. */\nfunction resolveMaxPages(entry) {\n  const v = entry?.max_pages;\n  if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES_CAP);\n  return DEFAULT_MAX_PAGES;\n}\n\n/**\n * Normalize a single Get on Board job (JSON:API resource). Exported for tests.\n *","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/providers/getonbrd.mjs#L63-L99","documentation":"assertGetonbrdUrl validates any URL destined for the Get on Board provider. When the string cannot be parsed by the WHATWG URL constructor (new URL throws on malformed input like missing scheme, spaces, or unescaped characters), the function throws this error. It is the first of three gates (parse, protocol, hostname) guarding against misconfigured or malicious portal entries reaching the fetch layer.","triggerScenarios":"A portals.yml entry supplies a careers_url or feed URL that is not a syntactically valid absolute URL — e.g. 'getonbrd.com/api/v0/...', 'https//www.getonbrd.com', or a URL containing spaces/unbalanced brackets — and assertGetonbrdUrl is called on it.","commonSituations":"Hand-edited portals.yml missing the https:// scheme; a URL pasted with trailing whitespace or typographic quotes; template placeholders (${...}) left unsubstituted in config; YAML folding turning a URL into a multi-line string.","solutions":["Prefix the URL with the scheme if missing — it must be a full absolute URL like https://www.getonbrd.com/api/v0/categories/programming/jobs","Trim whitespace and replace smart quotes/line breaks; quote the value in YAML so special characters don't break parsing","Validate locally with `new URL(value)` (or paste into a browser address bar) before adding it to portals.yml","If the entry doesn't need a custom URL, remove it and let the provider build the feed URL from the category slug"],"exampleFix":"// before\ncareers_url: www.getonbrd.com/api/v0/categories/programming/jobs\n// after\ncareers_url: https://www.getonbrd.com/api/v0/categories/programming/jobs","handlingStrategy":"validation","validationCode":"function isValidAbsoluteUrl(s) { try { new URL(s); return true; } catch { return false; } }\nif (!isValidAbsoluteUrl(entry.careers_url)) throw new Error(`entry ${entry.name}: careers_url is not a valid absolute URL`);","typeGuard":"function isHttpUrl(v) { return typeof v === 'string' && (() => { try { return !!new URL(v); } catch { return false; } })(); }","tryCatchPattern":"try {\n  assertGetonbrdUrl(url);\n} catch (e) {\n  if (String(e.message).includes('invalid URL')) {\n    console.error(`Config error: ${url} is not parseable — check scheme and characters`);\n    return null;\n  }\n  throw e;\n}","preventionTips":["Always store full absolute URLs with https:// scheme in portals.yml","Quote URL values in YAML so special characters don't break parsing","Run new URL(value) sanity checks in CI on config files","Avoid pasting URLs with surrounding whitespace or smart quotes"],"tags":["url-validation","config","getonbrd","invalid-url"],"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"}