santifer/career-ops · error · Error
jobvite: invalid URL: ${url}
Error message
jobvite: invalid URL: ${url} What it means
Thrown by assertJobviteHost when new URL(url) throws — the supplied string is not a parseable absolute URL. In the shipped provider, assertJobviteHost is only ever called on URLs built internally via the URL constructor (buildBoardFetchUrl from an encoded slug, buildFeedUrl via new URL + searchParams.set), which always parse. From the public contract this branch is therefore effectively unreachable; it is an SSRF defense-in-depth guard that would fire only if a constructed URL were somehow malformed (e.g. a slug/eid containing characters that break the constructor — encodeURIComponent and searchParams.set already prevent this).
Source
Thrown at providers/jobvite.mjs:97
// The XML feed inlines every job's FULL HTML description, so it is large and
// slow by construction rather than occasionally: Tyler Technologies returns
// 1.88 MB for 236 jobs in ~11s. That overshoots the shared 10s default in
// _http.mjs by a second, which aborted the whole tenant and reported it as a
// network failure. Sized to absorb a genuinely big tenant on a slow link; the
// board page (a normal HTML document) keeps the default.
const FEED_TIMEOUT_MS = 45_000;
/**
* Pin a URL to the two known Jobvite hosts over HTTPS.
* @param {string} url
*/
function assertJobviteHost(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`jobvite: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:')
throw new Error(`jobvite: URL must use HTTPS: ${url}`);
if (!ALLOWED_HOSTS.has(parsed.hostname))
throw new Error(`jobvite: untrusted hostname "${parsed.hostname}" — must be ${BOARD_HOST} or ${FEED_HOST}`);
return url;
}
// NaN-safe Date.parse → epoch ms.
/** @param {string} value */
function toEpochMs(value) {
if (!value) return undefined;
const parsed = Date.parse(value);
return Number.isNaN(parsed) ? undefined : parsed;
}
/**
* The vanity slug from a Jobvite careers URL, or null.View on GitHub (pinned to 9b17a8ac97)
Solutions
- Only ever pass URL-constructed strings to assertJobviteHost; pre-validate any caller input with new URL(...) in a try/catch.
- Keep BOARD_HOST/FEED_HOST as well-formed hostnames.
- Add a unit test asserting assertJobviteHost(buildFeedUrl(eid)) and assertJobviteHost(buildBoardFetchUrl(slug)) do not throw for representative inputs.
Example fix
// before — passing raw entry input
assertJobviteHost(entry.api);
// after — construct/validate first
let u;
try { u = new URL(entry.api); } catch { throw new Error('jobvite: bad api url'); }
assertJobviteHost(u.href); Defensive patterns
Strategy: validation
Validate before calling
// The shipped assert only ever receives constructor-built URLs.
// If you fork it onto caller input, pre-validate first:
function prevalidate(url) {
try { return new URL(url).href; }
catch { throw new Error(`jobvite: invalid URL: ${url}`); }
} Type guard
/** True for a parseable absolute URL string. */
function isAbsoluteUrl(value) {
if (typeof value !== 'string' || !value.trim()) return false;
try { new URL(value); return true; } catch { return false; }
} Try / catch
try {
return await jobviteProvider.fetch(entry, ctx);
} catch (err) {
if (/jobvite: invalid URL/.test(err.message)) {
// Only reachable if a constructed URL was malformed or caller input bypassed construction.
console.error(`jobvite: ${err.message} — pass only URL-constructed strings to assertJobviteHost`);
}
throw err;
} Prevention
- Only pass URL-constructed strings (new URL(...).href) into assertJobviteHost; never raw entry/user input.
- Keep BOARD_HOST/FEED_HOST as well-formed hostnames.
- Add a unit test that assertJobviteHost(buildFeedUrl(eid)) and assertJobviteHost(buildBoardFetchUrl(slug)) do not throw for representative inputs.
When it happens
Trigger: A fork that passes a raw user/entry string into assertJobviteHost instead of a constructor-built URL; a hypothetical slug/eid containing characters that defeat encodeURIComponent and new URL (not observed in practice); a build mangling the host constants BOARD_HOST/FEED_HOST.
Common situations: Extending the provider to accept an entry.api feed URL and routing it through the assert without pre-validation; editing BOARD_HOST/FEED_HOST to a malformed value.
Related errors
- comeet: invalid URL: ${redactToken(url)}
- comeet: URL must use HTTPS: ${redactToken(url)}
- comeet: untrusted hostname "${parsed.hostname}" — must be ${
- comeet: URL path must be the careers-api endpoint: ${redactT
- echojobs: invalid URL: ${url}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/771fb968851f7b53.
Report an issue: GitHub.