santifer/career-ops · error · Error
recruitee: invalid URL
Error message
recruitee: invalid URL: ${url} What it means
assertRecruiteeUrl() first requires the URL to be parseable by the URL constructor. If new URL(url) throws (malformed URL — missing scheme, illegal characters, empty string), this error is thrown before any host or protocol checks.
Solutions
- Prefix the URL with https:// if only the hostname was given
- Trim whitespace and re-check for typos or placeholder text in the careers_url field
- Validate the URL with new URL(raw) locally before adding it to portals.yml
Example fix
// before careers_url: acme.recruitee.com // after careers_url: https://acme.recruitee.com
Defensive patterns
Strategy: validation
Validate before calling
function isValidUrl(s) {
try { new URL(s); return true; } catch { return false; }
}
// call before invoking the provider:
if (!isValidUrl(entry.careers_url)) throw new Error(`Fix careers_url for ${entry.name}`); Type guard
function isHttpUrl(v) {
if (typeof v !== 'string') return false;
try { const u = new URL(v); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; }
} Try / catch
try {
assertRecruiteeUrl(entry.careers_url);
} catch (err) {
if (err.message.startsWith('recruitee: invalid URL')) {
console.error(`Add scheme: got "${entry.careers_url}", expected "https://..."`);
}
throw err;
} Prevention
- Always store absolute URLs with scheme in portals.yml
- Trim copy-pasted URLs to remove stray whitespace
- Run new URL(raw) as a local sanity check before committing config
When it happens
Trigger: assertRecruiteeUrl() (or fetch(), which routes through it) receives a string like "acme.recruitee.com" without a scheme, an empty string, a URL with spaces, or any otherwise unparseable value.
Common situations: A portals.yml entry records the bare hostname without https://; trailing whitespace or invisible characters in a copy-pasted URL; a careers_url field accidentally left blank or containing placeholder text.
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
- comeet: URL path must be the careers-api endpoint
- consider: needs an https careers_url on a public host
- csod: cannot resolve careersite URL for
- flowxtra: untrusted hostname
- flowxtra: URL must use HTTPS
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/31072749a861b73b.
Report an issue: GitHub.
Appendix: source
Thrown at providers/recruitee.mjs:19
// @ts-check
/** @typedef {import('./_types.js').Provider} Provider */
// Recruitee provider — hits the public per-tenant offers API.
// Auto-detects from careers_url pattern `https://<slug>.recruitee.com`.
// Per-tenant subdomains are the variable part — SSRF defence uses a
// regex match on `<safe-slug>.recruitee.com` rather than a static
// allowlist.
import { htmlToText } from './_html-to-text.mjs';
const RECRUITEE_HOST_RE = /^[a-z0-9][a-z0-9-]*\.recruitee\.com$/;
function assertRecruiteeUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`recruitee: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`recruitee: URL must use HTTPS: ${url}`);
if (!RECRUITEE_HOST_RE.test(parsed.hostname)) {
throw new Error(`recruitee: untrusted hostname "${parsed.hostname}" — must match <slug>.recruitee.com`);
}
return url;
}
function resolveApiUrl(entry) {
const raw = typeof entry.careers_url === 'string' ? entry.careers_url : '';
if (!raw) return null;
let parsed;
try {
parsed = new URL(raw);
} catch {
return null;
}
if (parsed.protocol !== 'https:') return null;View on GitHub (pinned to aac998c7ed)