santifer/career-ops · error · Error

workable: URL must use HTTPS

Error message

workable: URL must use HTTPS: ${url}

What it means

assertWorkableUrl validates URLs before the Workable provider fetches them. It parses the URL and rejects anything whose protocol is not 'https:'. This is part of the provider's SSRF guard: only HTTPS endpoints on allowlisted Workable hosts may be requested.

Solutions

  1. Change the URL scheme to https:// and retry
  2. If the host does not serve HTTPS, verify the hostname is a real Workable endpoint (apply.workable.com / workable.com)
  3. If the value comes from config, correct the careers_url there rather than bypassing the check

Example fix

// before
const url = 'http://apply.workable.com/acme/';
// after
const url = 'https://apply.workable.com/acme/';
Defensive patterns

Strategy: validation

Validate before calling

function isHttpsUrl(url) { try { return new URL(url).protocol === 'https:'; } catch { return false; } }
if (!isHttpsUrl(entry.careers_url)) throw new Error(`skip: careers_url must be https: ${entry.careers_url}`);

Type guard

const isHttpsUrl = (u) => { try { return new URL(u).protocol === 'https:'; } catch { return false; } };

Try / catch

try { await provider.fetch(entry, ctx); } catch (e) { if (String(e.message).startsWith('workable: URL must use HTTPS')) { console.warn(`Fix config for ${entry.name}: ${e.message}`); return []; } throw e; }

Prevention

When it happens

Trigger: Calling assertWorkableUrl, or configuring a tracked_companies entry whose careers_url/widget URL resolves to an http:// (or other non-https) scheme, e.g. 'http://apply.workable.com/acme/'.

Common situations: A portals.yml / tracker careers_url pasted from an old site that serves plain HTTP; a hand-built widgetUrlFor-style URL with 'http://' hardcoded; a redirect target captured as http.

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/1c52a8e34844ec00. Report an issue: GitHub.

Appendix: source

Thrown at providers/workable.mjs:116

// Process-wide serialization: apply.workable.com fronts every tenant on the
// same host, so this process never needs more than one in-flight request to
// it at a time.
let workableQueue = Promise.resolve();
function serialized(fn) {
  const result = workableQueue.then(fn, fn);
  workableQueue = result.then(() => undefined, () => undefined);
  return result;
}

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

/**
 * Extract the account slug from a tracked_companies entry's careers_url.
 * @returns {string|null}
 */
export function resolveWorkableSlug(entry) {
  const raw = entry && typeof entry.careers_url === 'string' ? entry.careers_url : '';
  if (!raw) return null;
  let parsed;
  try {
    parsed = new URL(raw);
  } catch {
    return null;

View on GitHub (pinned to aac998c7ed)