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

  1. Prefix the URL with https:// if only the hostname was given
  2. Trim whitespace and re-check for typos or placeholder text in the careers_url field
  3. 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

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


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)