santifer/career-ops · error · Error
jobbankca: invalid URL: ${url}
Error message
jobbankca: invalid URL: ${url} What it means
jobbankca's assertJobBankUrl validates every URL before it is fetched. It first attempts to parse the string with the URL constructor; if parsing fails entirely (malformed URL), it throws this error. This is a fail-fast guard so downstream fetch logic only ever sees a structurally valid URL.
Source
Thrown at providers/jobbankca.mjs:98
const keywords = Array.isArray(cfg.keywords)
? cfg.keywords.filter((k) => typeof k === 'string' && k.trim()).map((k) => k.trim())
: [];
return { keywords };
}
/** @param {string} keyword @param {number} page */
export function buildFeedUrl(keyword, page) {
const params = new URLSearchParams({ searchstring: keyword, locationstring: '', page: String(page) });
return `${FEED_URL}?${params.toString()}`;
}
/** @param {string} url */
export function assertJobBankUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`jobbankca: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`jobbankca: URL must use HTTPS: ${url}`);
if (parsed.hostname !== TRUSTED_HOST) {
throw new Error(`jobbankca: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
}
return url;
}
// Resolve an Atom element's inner text: unwrap CDATA, else decode entities.
function extractText(inner) {
const cdata = inner.match(/^\s*<!\[CDATA\[([\s\S]*?)\]\]>\s*$/);
if (cdata) return cdata[1].trim();
return decodeEntities(inner).trim();
}
function tagText(block, tag) {
const m = block.match(new RegExp(`<${tag}\\b[^>]*>([\\s\\S]*?)</${tag}>`, 'i'));
return m ? extractText(m[1]) : '';View on GitHub (pinned to 1696bec4d0)
Solutions
- Print the exact url value being passed and fix the malformed string in the provider config (e.g. add the https:// scheme)
- Ensure the config key/env var feeding the URL is actually set (an undefined variable renders as the literal string 'undefined')
- Use new URL(url) yourself in a try/catch to validate before calling, and log the cause
- If building URLs programmatically, use new URL('https://...', base) or URLSearchParams instead of string concatenation
Example fix
// before fetchFeed(process.env.JOBBANK_FEED) // 'undefined' // after const feedUrl = process.env.JOBBANK_FEED ?? 'https://jobbank.canada.ca/atom.xml'; new URL(feedUrl); // throws early with a clearer cause if still bad fetchFeed(feedUrl);
Defensive patterns
Strategy: validation
Validate before calling
function isValidUrl(u) { try { new URL(u); return true; } catch { return false; } }
if (!isValidUrl(cfg.url)) throw new Error(`config: not a valid URL: ${cfg.url}`); Type guard
function isHttpUrl(v) {
if (typeof v !== 'string') return false;
try { const u = new URL(v); return !!u.protocol && !!u.hostname; } catch { return false; }
} Try / catch
try {
assertJobBankUrl(url);
} catch (e) {
if (e.message.includes('invalid URL')) {
console.error(`Bad feed URL in config: ${url}`);
return; // skip entry, don't crash the scan
}
throw e;
} Prevention
- Always store absolute URLs with explicit https:// in portals.yml
- Interpolate env vars with defaults so 'undefined' never becomes part of a URL
- Run new URL() on config values at load time, not fetch time
- Avoid string-concatenating URLs; use the URL constructor with a base
When it happens
Trigger: Calling assertJobBankUrl(url) (directly or via a fetch that passes a configured URL) with a string that is not a parseable absolute URL — e.g. missing scheme, whitespace, 'jobbank_CANADA' as URL, an empty string, or a template literal that interpolated to garbage.
Common situations: Config typo in portals.yml (missing 'https://'), env var for a feed URL unset so 'undefined' gets interpolated into the URL string, or a relative path like '/search?f=...' passed where an absolute URL is required.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- getonbrd: invalid URL: ${url}
- getro: ${entry.name} needs an https careers_url
- glints: invalid URL: ${url}
- jobbankca: URL must use HTTPS: ${url}
- jobbankca: entry "${entry?.name || '(unnamed)'}" has no jobb
AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01).
Data as JSON: /api/errors/4138ddbc8a79d767.
Report an issue: GitHub.