santifer/career-ops · error · Error

workable: invalid URL: ${url}

Error message

workable: invalid URL: ${url}

What it means

assertWorkableUrl pins Workable requests to apply.workable.com (ALLOWED_WORKABLE_HOSTS). This branch fires when new URL(url) throws on a URL built from widgetUrlFor(slug) or feedUrlFor(slug). Because the slug is first validated by SLUG_RE (^[A-Za-z0-9][A-Za-z0-9_-]*$), the only realistic way to hit this is a maintainer breaking the URL templates — not a user-config error.

Source

Thrown at providers/workable.mjs:114

  throw lastErr;
}

// 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);

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Restore the widget template to https://apply.workable.com/api/v1/widget/accounts/${slug}?details=true.
  2. Unit-test assertWorkableUrl(widgetUrlFor("acme")).

Example fix

// before
const widgetUrlFor = (slug) => `apply.workable.com/api/v1/widget/accounts/${slug}`;
// after
const widgetUrlFor = (slug) => `https://apply.workable.com/api/v1/widget/accounts/${slug}?details=true`;
Defensive patterns

Strategy: validation

Validate before calling

for (const tpl of [widgetUrlFor, feedUrlFor]) {
  try { new URL(tpl("acme")); }
  catch { throw new Error("workable: URL template produced an unparseable URL"); }
}

Type guard

const isAbsoluteUrl = (s) => { try { new URL(s); return true; } catch { return false; } };

Prevention

When it happens

Trigger: A maintainer edits widgetUrlFor/feedUrlFor and drops the scheme or otherwise makes it unparseable; a bad merge. The slug is sanitized before interpolation, so crafted careers_url values cannot reach here.

Common situations: A refactor of the URL templates; running a patched fork.

Related errors


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