santifer/career-ops · error · Error
nofluffjobs: invalid URL: ${url}
Error message
nofluffjobs: invalid URL: ${url} What it means
Thrown by nofluffjobs' assertNoFluffUrl() when new URL(url) throws — the URL is syntactically invalid. This is the first gate of a three-stage SSRF guard (valid URL → HTTPS → trusted host) that constrains all NoFluffJobs API calls to nofluffjobs.com. The guard is invoked from both detectUrl() and fetch().
Source
Thrown at providers/nofluffjobs.mjs:19
// @ts-check
/** @typedef {import('./_types.js').Provider} Provider */
// NoFluffJobs provider — hits the public search posting API.
// It intentionally returns only the core scanner job fields; richer skill and
// salary metadata can be added later if the provider contract is expanded.
const ALLOWED_HOSTS = new Set(['nofluffjobs.com']);
const API_URL = 'https://nofluffjobs.com/api/search/posting';
const JOB_BASE = 'https://nofluffjobs.com/pl/job/';
const PAGE_SIZE = 20;
const MAX_PAGES = 5;
function assertNoFluffUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`nofluffjobs: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`nofluffjobs: URL must use HTTPS: ${url}`);
if (!ALLOWED_HOSTS.has(parsed.hostname)) {
throw new Error(`nofluffjobs: untrusted hostname "${parsed.hostname}" — must be nofluffjobs.com`);
}
return parsed;
}
function detectUrl(entry) {
const url = entry.api || entry.careers_url || '';
if (typeof url !== 'string' || !url.trim()) return null;
try {
return { url: assertNoFluffUrl(url).href };
} catch {
return null;
}
}
View on GitHub (pinned to 9b17a8ac97)
Solutions
- Log the url value passed to assertNoFluffUrl to identify the malformed string.
- Ensure the portals.yml entry for nofluffjobs has api or careers_url as a fully-qualified https://nofluffjobs.com/... URL.
- If no api/careers_url is needed (the provider uses API_URL constant internally), remove the misconfigured field so detectUrl() returns the default.
Example fix
// before
// portals.yml has a typo or missing scheme:
job_boards:
nofluff:
provider: nofluffjobs
api: 'nofluffjobs.com/api/search/posting' // missing https://
// after
job_boards:
nofluff:
provider: nofluffjobs
api: 'https://nofluffjobs.com/api/search/posting' Defensive patterns
Strategy: validation
Validate before calling
/** Validate a URL string is parseable before passing to assertNoFluffUrl. */
function isValidUrlString(url) {
return typeof url === 'string'
&& url.length > 0
&& /^https?:\/\/.+/i.test(url)
&& (() => { try { new URL(url); return true; } catch { return false; } })();
}
if (!isValidUrlString(entry.api) && !isValidUrlString(entry.careers_url)) {
console.warn(`nofluffjobs entry ${entry.name} has no valid URL`);
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 {
await nofluffProvider.fetch(entry, ctx);
} catch (err) {
if (String(err.message).startsWith('nofluffjobs: invalid URL')) {
console.warn(`skipping nofluffjobs entry ${entry.name}: malformed URL`);
continue;
}
throw err;
} Prevention
- Validate URL fields in portals.yml at config-load time.
- Always include https:// scheme in portal URLs.
- Call detect(entry) before fetch() and skip null results.
When it happens
Trigger: Called with an unparseable URL string: empty string, undefined, a value with spaces/control characters, or a schemeless path like 'nofluffjobs.com/api/search/posting'. In detectUrl() this is caught and returns null, but direct calls to assertNoFluffUrl() (e.g. from fetch() or tests) surface the throw.
Common situations: A portals.yml entry has api or careers_url left empty, set to null, or containing a typo. A config migration or YAML parsing edge case produces a non-string value. A developer passes a relative path expecting it to be resolved against a base URL (this provider does no base resolution).
Related errors
- nofluffjobs: 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/b9b00543349d5c8f.
Report an issue: GitHub.