santifer/career-ops · error · Error
pythonorg: invalid URL
Error message
pythonorg: invalid URL: ${url} What it means
assertPythonOrgUrl validates any URL handed to the python.org jobs-feed provider. When the input cannot be parsed by the URL constructor at all (malformed syntax, missing scheme), it throws 'pythonorg: invalid URL: {url}'. It is the first of three checks, before the HTTPS and trusted-host checks, so configuration typos surface as a clear provider-namespaced error.
Solutions
- Fix the URL string so it is a valid absolute URL, e.g. 'https://www.python.org/jobs/feed/rss/'
- Add the missing scheme (https://) — the most common cause is a scheme-less host:port/path string
- Log/inspect the exact value passed in; unset or malformed env/config values are frequent culprits
- Wrap calls in a check like `new URL(url)` (or the defense validation code) before invoking the provider
Example fix
// before assertPythonOrgUrl(config.feedUrl); // 'python.org/jobs/feed/rss/' // after const feedUrl = new URL(config.feedUrl).href; // throws with a clear syntax error, or fix config to 'https://www.python.org/jobs/feed/rss/' assertPythonOrgUrl(feedUrl);
Defensive patterns
Strategy: validation
Validate before calling
export function isValidPythonOrgUrl(url) {
try { new URL(url); return true; } catch { return false; }
}
// call before the provider: if (!isValidPythonOrgUrl(cfg.feedUrl)) throw new Error(`bad feedUrl: ${cfg.feedUrl}`) Type guard
function isAbsoluteHttpUrl(value) {
if (typeof value !== 'string') return false;
try { const u = new URL(value); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; }
} Try / catch
try {
assertPythonOrgUrl(cfg.feedUrl);
} catch (e) {
if (e.message.startsWith('pythonorg: invalid URL')) {
console.error(`Config error: feedUrl '${cfg.feedUrl}' is not a parseable absolute URL — add the https:// scheme`);
process.exitCode = 1;
} else throw e;
} Prevention
- Always store feed URLs as full absolute strings including the scheme in portals.yml
- Validate all job-board URLs at config-load time with `new URL()` so failures surface once, early
- Watch for env-var interpolation producing empty/partial values; assert non-empty before use
- Use the canonical feed URL 'https://www.python.org/jobs/feed/rss/' rather than hand-assembling paths
When it happens
Trigger: Calling assertPythonOrgUrl with a string the URL constructor rejects — e.g. 'python.org/jobs/feed/rss/' (no scheme), 'https://' (empty host), 'not a url', or a non-string coerced to something unparseable.
Common situations: A portals.yml job_boards entry with a typo'd or scheme-less URL; reading the URL from an env var that is unset or partially interpolated; concatenating base + path strings incorrectly; passing user-supplied input unvalidated.
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
- a16z-speedrun-talent: invalid URL
- agentic-jobs: invalid URL
- collage: API URL must be /v1/positions/<job-site-address>
- collage: invalid URL
- eightfold: cannot derive API URL for
AI-assisted analysis of santifer/career-ops@e7abd431fc (2026-09-22).
Data as JSON: /api/errors/98011365bcb4c301.
Report an issue: GitHub.
Appendix: source
Thrown at providers/pythonorg.mjs:26
// Python.org provider — the board-wide public RSS jobs feed at
// https://www.python.org/jobs/feed/rss/ (official Python Software Foundation job board).
// The feed is public, no-auth, and RSS 2.0 XML.
//
// Each <item> exposes <title> (typically "{Role}, {Company}"), <link>,
// and <description> (the first line typically contains the location).
//
// Wire in via a `job_boards:` entry with `provider: pythonorg`.
const FEED_URL = 'https://www.python.org/jobs/feed/rss/';
const TRUSTED_HOST = 'python.org';
/** @param {string} url */
export function assertPythonOrgUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`pythonorg: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`pythonorg: URL must use HTTPS: ${url}`);
const host = parsed.hostname.toLowerCase();
const trusted = host === TRUSTED_HOST || host.endsWith(`.${TRUSTED_HOST}`);
if (!trusted) {
throw new Error(`pythonorg: 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) {View on GitHub (pinned to e7abd431fc)