santifer/career-ops · error

getonbrd: invalid URL

Error message

getonbrd: invalid URL: ${url}

What it means

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.

Solutions

  1. 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
  2. Trim whitespace and replace smart quotes/line breaks; quote the value in YAML so special characters don't break parsing
  3. Validate locally with `new URL(value)` (or paste into a browser address bar) before adding it to portals.yml
  4. If the entry doesn't need a custom URL, remove it and let the provider build the feed URL from the category slug

Example fix

// before
careers_url: www.getonbrd.com/api/v0/categories/programming/jobs
// after
careers_url: https://www.getonbrd.com/api/v0/categories/programming/jobs
Defensive patterns

Strategy: validation

Validate before calling

function isValidAbsoluteUrl(s) { try { new URL(s); return true; } catch { return false; } }
if (!isValidAbsoluteUrl(entry.careers_url)) throw new Error(`entry ${entry.name}: careers_url is not a valid absolute URL`);

Type guard

function isHttpUrl(v) { return typeof v === 'string' && (() => { try { return !!new URL(v); } catch { return false; } })(); }

Try / catch

try {
  assertGetonbrdUrl(url);
} catch (e) {
  if (String(e.message).includes('invalid URL')) {
    console.error(`Config error: ${url} is not parseable — check scheme and characters`);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/d5558b9ac288e506. Report an issue: GitHub.

Appendix: source

Thrown at providers/getonbrd.mjs:81

  }
  if (!out.length) {
    throw new Error('getonbrd: `categories` is empty — omit it to use the "programming" default');
  }
  if (out.length > MAX_CATEGORIES) {
    throw new Error(
      `getonbrd: ${out.length} categories configured — cap is ${MAX_CATEGORIES} (each one costs up to max_pages requests)`,
    );
  }
  return out;
}

/** @param {string} url */
function assertGetonbrdUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`getonbrd: invalid URL: ${url}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`getonbrd: URL must use HTTPS: ${url}`);
  if (parsed.hostname !== TRUSTED_HOST) {
    throw new Error(`getonbrd: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
  }
  return url;
}

/** Resolve the page cap: a positive integer `max_pages` on the entry, capped. */
function resolveMaxPages(entry) {
  const v = entry?.max_pages;
  if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES_CAP);
  return DEFAULT_MAX_PAGES;
}

/**
 * Normalize a single Get on Board job (JSON:API resource). Exported for tests.
 *

View on GitHub (pinned to aac998c7ed)