santifer/career-ops · error · Error
recruitee: URL must use HTTPS
Error message
recruitee: URL must use HTTPS: ${url} What it means
URL scheme guard in the Recruitee provider (assertRecruiteeUrl): the parsed per-tenant careers URL parsed fine but its protocol is not https:. Part of the SSRF defence stack that also checks the host against the <safe-slug>.recruitee.com pattern; the scheme check simply comes later. The input at fault is the careers_url for the tenant.
Solutions
- Change the scheme to https:// in the entry
- Verify Recruitee serves the tenant over HTTPS (it always does for *.recruitee.com)
- Re-run the scan after fixing the URL
Example fix
// before careers_url: http://acme.recruitee.com // after careers_url: https://acme.recruitee.com
Defensive patterns
Strategy: validation
Validate before calling
function isHttpsUrl(s) {
try { return new URL(s).protocol === 'https:'; } catch { return false; }
}
if (!isHttpsUrl(entry.careers_url)) throw new Error(`Use https:// for ${entry.name}`); Type guard
function isSecureUrl(v) {
try { return v instanceof URL ? v.protocol === 'https:' : new URL(String(v)).protocol === 'https:'; } catch { return false; }
} Try / catch
try {
assertRecruiteeUrl(entry.careers_url);
} catch (err) {
if (err.message.startsWith('recruitee: URL must use HTTPS')) {
const fixed = entry.careers_url.replace(/^http:/, 'https:');
console.warn(`Upgraded ${entry.name} careers_url to ${fixed}`);
}
throw err;
} Prevention
- Never enter http:// URLs for ATS boards; Recruitee tenants are always HTTPS
- Add a config check that rejects non-https careers_url at edit time
- Treat http→https upgrades as safe — but re-verify the board after the change
When it happens
Trigger: A careers_url like http://acme.recruitee.com or any non-https scheme (ftp:, file:) reaches assertRecruiteeUrl via detect()/fetch().
Common situations: A manually edited portals.yml entry uses http:// because the careers page redirected; an old config predating an HTTPS migration; tooling that lowercases or strips the scheme.
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: URL must use HTTPS
- agentic-jobs: URL must use HTTPS
- collage: URL must use HTTPS
- getonbrd: URL must use HTTPS
- glints: URL must use HTTPS
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/ba0bb1cf4350a99d.
Report an issue: GitHub.
Appendix: source
Thrown at providers/recruitee.mjs:21
// 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;
if (!RECRUITEE_HOST_RE.test(parsed.hostname)) return null;
return `https://${parsed.hostname}/api/offers/`;View on GitHub (pinned to aac998c7ed)