santifer/career-ops · error · Error
nodesk: invalid URL: ${url}
Error message
nodesk: invalid URL: ${url} What it means
Thrown by nodesk's assertNodeskUrl() when new URL(url) raises an exception — the URL string is syntactically unparseable by the WHATWG URL parser. This is the first gate in a three-stage SSRF guard (valid URL → HTTPS → trusted host) that keeps all fetches pinned to nodesk.co. It fires before any network request is made.
Source
Thrown at providers/nodesk.mjs:20
/** @typedef {import('./_types.js').Provider} Provider */
// NoDesk provider - board-wide RSS feed
// (https://nodesk.co/remote-jobs/index.xml). The feed is public, no-auth,
// and XML, so it is parsed in-process with the same tiny tag extractor
// approach as providers/personio.mjs rather than adding an XML dependency.
//
// Wire in via a `job_boards:` entry with `provider: nodesk`.
const FEED_URL = 'https://nodesk.co/remote-jobs/index.xml';
const TRUSTED_HOST = 'nodesk.co';
/** @param {string} url */
function assertNodeskUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`nodesk: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`nodesk: URL must use HTTPS: ${url}`);
if (parsed.hostname !== TRUSTED_HOST) {
throw new Error(`nodesk: untrusted hostname "${parsed.hostname}" - must be ${TRUSTED_HOST}`);
}
return url;
}
// NaN-safe Date.parse - `|| undefined` would also coerce a valid epoch 0.
function toEpochMs(value) {
if (!value) return undefined;
const parsed = Date.parse(value);
return Number.isNaN(parsed) ? undefined : parsed;
}
function fallbackCompany(entry) {
return typeof entry?.name === 'string' && entry.name.trim() ? entry.name.trim() : 'NoDesk';
}View on GitHub (pinned to 9b17a8ac97)
Solutions
- Inspect the value being passed to assertNodeskUrl — log or debug the url argument to see the exact malformed string.
- If the URL comes from portals.yml, ensure it is a fully-qualified https:// URL (the provider uses the constant FEED_URL by default, so a configured override is the likely culprit).
- If the constant FEED_URL itself was edited, restore it to 'https://nodesk.co/remote-jobs/index.xml'.
- Add a pre-check in the caller: if (typeof url !== 'string' || !url.startsWith('http')) return null in detect() before reaching fetch().
Example fix
// before
const FEED_URL = 'https://nodesk.co/remote-jobs/index.xml';
// if someone overrides to a bare path:
assertNodeskUrl('nodesk.co/remote-jobs/index.xml'); // throws
// after — ensure a scheme before parsing
function assertNodeskUrl(url) {
const normalized = typeof url === 'string' && !url.match(/^[a-z]+:///i) ? `https://${url}` : url;
let parsed;
try { parsed = new URL(normalized); } catch {
throw new Error(`nodesk: invalid URL: ${url}`);
}
// ... rest of checks
} Defensive patterns
Strategy: validation
Validate before calling
/** Validate a URL string is parseable before passing to assertNodeskUrl. */
function isValidUrlString(url) {
return typeof url === 'string'
&& url.length > 0
&& /^https?:\/\/.+/i.test(url)
&& (() => { try { new URL(url); return true; } catch { return false; } })();
}
// before calling the provider:
if (!isValidUrlString(entry.api)) {
console.warn(`nodesk entry ${entry.name} has invalid URL, skipping`);
continue;
} Type guard
/** @param {unknown} url @returns {url is string} */
function isParseableUrl(url) {
if (typeof url !== 'string' || !url) return false;
try { new URL(url); return true; } catch { return false; }
} Try / catch
try {
const jobs = await nodeskProvider.fetch(entry, ctx);
} catch (err) {
if (String(err.message).startsWith('nodesk: invalid URL')) {
console.warn(`skipping nodesk entry ${entry.name}: malformed URL`);
continue;
}
throw err;
} Prevention
- Validate all URLs in portals.yml at config-load time with a schema validator.
- Always include the https:// scheme in portal entry URLs.
- Use detect() to filter entries before calling fetch() — entries returning null from detect() should be skipped.
When it happens
Trigger: Called with a value that new URL() cannot parse: empty string, undefined coerced to 'undefined', a URL with embedded spaces or control characters, a schemeless bare path like 'remote-jobs/index.xml', or a double-encoded malformed string. In practice this is reached when entry.api or a dynamically built URL is missing/malformed and bypasses an earlier detect() null-return.
Common situations: A portals.yml nodesk entry has careers_url or api set to an empty string, null, or a typo without a scheme (e.g. 'nodesk.co/remote-jobs/index.xml' without https://). Also occurs when a config migration script writes a non-string value that gets stringified to '[object Object]'. Since FEED_URL is a constant, this typically only fires if the constant is changed or assertNodeskUrl is called with a user-supplied URL.
Related errors
- nodesk: URL must use HTTPS: ${url}
- flowxtra: untrusted hostname "${parsed.hostname}" — must be
- gem: invalid URL: ${url}
- gem: URL must use HTTPS: ${url}
- gem: untrusted hostname "${parsed.hostname}" — must be one o
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/521492b53f9788db.
Report an issue: GitHub.