santifer/career-ops · error · Error
landingjobs: invalid URL
Error message
landingjobs: invalid URL: ${url} What it means
The landingjobs provider validates every URL before use via assertLandingUrl. When the URL cannot be parsed by the WHATWG URL constructor (new URL throws), the provider throws this error to fail fast instead of making a bogus network request. It guards against malformed config values in portals.yml and programmatic misuse of the provider.
Solutions
- Fix the URL string so it is absolute and well-formed, including the scheme: https://landingjobs.io/...
- If it comes from config, check the portals.yml entry for typos, missing scheme, or unresolved placeholders.
- Pre-validate with new URL(url) in a try/catch before passing it to the provider.
- Log or print the exact value being passed — the error interpolates it verbatim, so compare against the expected value.
Example fix
// before
assertLandingUrl('landingjobs.io/jobs');
// after
assertLandingUrl('https://landingjobs.co/jobs'); Defensive patterns
Strategy: validation
Validate before calling
function isValidUrl(u) { try { new URL(u); return true; } catch { return false; } }
if (!isValidUrl(url)) throw new Error(`skipping provider: invalid URL ${url}`); Type guard
function isHttpUrl(v) { return typeof v === 'string' && (() => { try { new URL(v); return true; } catch { return false; } })(); } Try / catch
try {
provider.fetch(entry, ctx);
} catch (e) {
if (e.message.startsWith('landingjobs: invalid URL')) {
console.error(`Bad config URL: ${e.message}`);
return null;
}
throw e;
} Prevention
- Validate all careers_url values in portals.yml at startup with new URL()
- Quote URLs in YAML and always include the scheme
- Add a config lint step that rejects placeholder tokens like '${' in URLs
- Fail soft per-entry so one bad URL doesn't abort the whole scan
When it happens
Trigger: Calling assertLandingUrl (directly or via the provider's fetch path) with a string that new URL() rejects: an empty string, a URL missing a scheme (e.g. 'landingjobs.io/jobs'), whitespace, or otherwise malformed syntax.
Common situations: A portals.yml entry with an unquoted or partially filled careers_url, a template placeholder left unresolved (e.g. '${url}' literally in config), or code passing a path-only string instead of a full URL.
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
- garena: is not a usable URL segment
- larajobs: invalid URL
- lever: invalid URL
- nodesk: invalid URL
- nofluffjobs: invalid URL
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/8f4c9e0c56b3216a.
Report an issue: GitHub.
Appendix: source
Thrown at providers/landingjobs.mjs:26
// created_at, type, tags, gross_salary_low, gross_salary_high, ... }
//
// NOTE: the v1 feed carries no company-name field — the employer slug only
// appears in the posting URL path (`https://landing.jobs/at/<slug>/<job>`), so
// `company` is derived best-effort from that slug (humanized) and falls back to
// the portal entry name. The whole active set is returned in one call.
//
// Wire in via a `job_boards:` entry with `provider: landingjobs`.
const FEED_URL = 'https://landing.jobs/api/v1/jobs';
const TRUSTED_HOST = 'landing.jobs';
/** @param {string} url */
function assertLandingUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`landingjobs: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`landingjobs: URL must use HTTPS: ${url}`);
if (parsed.hostname !== TRUSTED_HOST) {
throw new Error(`landingjobs: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
}
return url;
}
// NaN-safe Date.parse.
function toEpochMs(value) {
if (typeof value !== 'string' || !value) return undefined;
const parsed = Date.parse(value);
return Number.isNaN(parsed) ? undefined : parsed;
}
/**
* Derive a best-effort company name from a Landing.jobs posting URL.
* Posting URLs are `https://landing.jobs/at/<slug>/<job>`; the `<slug>` isView on GitHub (pinned to aac998c7ed)