santifer/career-ops · error · Error
a16z-speedrun-talent: invalid URL
Error message
a16z-speedrun-talent: invalid URL: ${url} What it means
assertFeedUrl in providers/a16z-speedrun-talent.mjs throws this when the given URL cannot be parsed by the URL constructor at all (malformed URL syntax). The provider validates every feed URL before fetching, so syntactically broken URLs are rejected with the original string embedded in the message. This is the first of three checks: parse, then HTTPS, then trusted hostname.
Solutions
- Fix the URL string so it is a valid absolute URL, e.g. prepend https:// if the scheme is missing.
- Trim whitespace/newlines that YAML folding or copying may have introduced.
- Check the config source for an unset variable/placeholder interpolating into the URL.
- Test with `new URL(url)` in a REPL to see the exact parse failure before retrying.
Example fix
// before
fetchSpeedrunFeed(config.feedHost + '/api/jobs') // 'example.com/api/jobs' — no scheme
// after
fetchSpeedrunFeed('https://example.com/api/jobs') Defensive patterns
Strategy: validation
Validate before calling
let parsed;
try { parsed = new URL(rawUrl); }
catch { throw new Error(`invalid feed URL: ${rawUrl}`); }
if (parsed.protocol !== 'https:') throw new Error('feed URL must be https'); Type guard
function isParsableUrl(s) {
try { new URL(s); return true; } catch { return false; }
} Try / catch
try {
await fetchSpeedrunFeed(url);
} catch (e) {
if (String(e.message).startsWith('a16z-speedrun-talent: invalid URL')) {
console.error(`Malformed feed URL in config: ${url}`);
return null;
} else throw e;
} Prevention
- Always store feed URLs as full absolute https:// URLs in config.
- Trim YAML-folded strings and check for placeholder leftovers at startup.
- Validate every configured URL with new URL() during config load, before the provider runs.
- Avoid building URLs by string concatenation of unvalidated parts.
When it happens
Trigger: Passing a URL string that new URL() rejects — missing scheme ('a16z.com/feed'), spaces or illegal characters, an empty string, or a config value that was never a URL (e.g. a path like '/feed' or a placeholder).
Common situations: portals.yml entry with a relative URL or missing https://; whitespace/newline from YAML folding; template placeholder left unsubstituted; env var not set so the URL interpolates to 'undefined/feed'.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- agentic-jobs: invalid URL
- eightfold: cannot derive API URL for
- 4dayweek: untrusted hostname
- a16z-speedrun-talent: untrusted hostname
- a16z-speedrun-talent: URL must use HTTPS
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/7ce2acb340c123aa.
Report an issue: GitHub.
Appendix: source
Thrown at providers/a16z-speedrun-talent.mjs:45
const TRUSTED_HOST = 'speedrun-talent-network.com';
const PER_PAGE = 50;
const DEFAULT_MAX_PAGES = 6; // × PER_PAGE = the 300-job default scan
// Runaway bound, not a coverage target: iteration already stops at the
// feed's reported total_pages (or, when the feed omits it, a short page), so
// on an honest feed the cap costs nothing and full-board sweeps keep working
// as the board grows.
// It only bites a misbehaving feed or an absurd max_pages entry — so it
// sits well above plausible board size (~353 pages / ~17.6k jobs as of
// 2026-08), same policy as workday.mjs's cap.
const MAX_PAGES_CAP = 1000;
/** @param {string} url */
function assertFeedUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`a16z-speedrun-talent: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`a16z-speedrun-talent: URL must use HTTPS: ${url}`);
if (parsed.hostname !== TRUSTED_HOST) {
throw new Error(`a16z-speedrun-talent: untrusted hostname "${parsed.hostname}" — must be ${TRUSTED_HOST}`);
}
return url;
}
/** Resolve the page cap: a positive integer `max_pages` on the entry, capped. */
function resolveMaxPages(entry) {
const v = entry?.max_pages;
if (Number.isInteger(v) && v > 0) return Math.min(v, MAX_PAGES_CAP);
return DEFAULT_MAX_PAGES;
}
/** Optional server-side query: `q:` on the entry, else joined `keywords:`. */
function resolveQuery(entry) {
if (typeof entry?.q === 'string' && entry.q.trim()) return entry.q.trim();View on GitHub (pinned to aac998c7ed)