santifer/career-ops · error · Error

smartrecruiters: URL must use HTTPS: ${url}

Error message

smartrecruiters: URL must use HTTPS: ${url}

What it means

assertSmartRecruitersUrl rejects any URL whose protocol is not 'https:'. The check runs after the URL parses. Since the API URL is built from a constant base on api.smartrecruiters.com, this firing means the base was altered to http or an externally-supplied http URL reached the guard.

Source

Thrown at providers/smartrecruiters.mjs:22

// SmartRecruiters provider — hits the public postings API.
// Auto-detects from careers_url pattern
// `https://(careers|jobs).smartrecruiters.com/<slug>`. A tracked_companies
// entry can also set `provider: smartrecruiters` explicitly to bypass
// detection (useful when the public careers URL is a branded custom domain).

const ALLOWED_SMARTRECRUITERS_HOSTS = new Set(['api.smartrecruiters.com']);
const SR_CAREERS_HOSTS = new Set(['careers.smartrecruiters.com', 'jobs.smartrecruiters.com']);
const SR_PAGE_SIZE = 100;
const SR_MAX_PAGES = 50;  // safety cap (5000 postings @ 100/page)

function assertSmartRecruitersUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`smartrecruiters: invalid URL: ${url}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`smartrecruiters: URL must use HTTPS: ${url}`);
  if (!ALLOWED_SMARTRECRUITERS_HOSTS.has(parsed.hostname)) {
    throw new Error(`smartrecruiters: untrusted hostname "${parsed.hostname}" — must be one of: ${[...ALLOWED_SMARTRECRUITERS_HOSTS].join(', ')}`);
  }
  return url;
}

function resolveSlug(entry) {
  // entry.api takes precedence over careers_url (mirrors greenhouse/ashby) so a
  // branded page (e.g. https://jobs.continental.com) can stay as careers_url
  // while the SmartRecruiters slug is pinned via
  // api: https://careers.smartrecruiters.com/<slug> in portals.yml.
  for (const raw of [entry.api, entry.careers_url]) {
    if (typeof raw !== 'string' || !raw) continue;
    let parsed;
    try {
      parsed = new URL(raw);
    } catch {
      continue;

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Restore the API base to its https:// form.
  2. If a URL came from outside, upgrade: url.replace(/^http:/, 'https:').
  3. Audit for any http://api.smartrecruiters.com references in config or code.

Example fix

// before
const base = 'http://api.smartrecruiters.com/v1/companies';
// after
const base = 'https://api.smartrecruiters.com/v1/companies';
Defensive patterns

Strategy: validation

Validate before calling

function ensureHttps(raw) {
  return typeof raw === 'string' ? raw.replace(/^http:\/\//i, 'https://') : raw;
}
// Pin the smartrecruiters API base
const SR_API_BASE = 'https://api.smartrecruiters.com';

Type guard

null

Try / catch

try {
  await provider.fetch(entry, ctx);
} catch (e) {
  if (/must use HTTPS/.test(e.message)) {
    console.error('[bug] smartrecruiters API base is http — restore https');
  } else throw e;
}

Prevention

When it happens

Trigger: The API base constant was changed to http://; an external caller passed an http URL; a redirect or scraped link captured the http variant.

Common situations: A development override switched the scheme to http; a config or environment variable altered the base URL.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/0c3f3e800f2dd185. Report an issue: GitHub.