santifer/career-ops · error · Error
workable: cannot derive feed URL for ${entry.name}
Error message
workable: cannot derive feed URL for ${entry.name} What it means
Workable auto-detects an account from a careers_url matching https://apply.workable.com/<slug>; resolveWorkableSlug returns null when the URL is absent, not https, not on apply.workable.com, or the slug fails SLUG_RE. fetch() then throws because it has no slug to build the widget/feed URL from.
Source
Thrown at providers/workable.mjs:157
if (!slug || !SLUG_RE.test(slug)) return null;
return slug;
}
const widgetUrlFor = (slug) => `https://apply.workable.com/api/v1/widget/accounts/${slug}?details=true`;
const feedUrlFor = (slug) => `https://apply.workable.com/${slug}/jobs.md`;
/** @type {Provider} */
export default {
id: 'workable',
detect(entry) {
const slug = resolveWorkableSlug(entry);
return slug ? { url: widgetUrlFor(slug) } : null;
},
async fetch(entry, ctx) {
const slug = resolveWorkableSlug(entry);
if (!slug) throw new Error(`workable: cannot derive feed URL for ${entry.name}`);
const referer = `https://apply.workable.com/${slug}/`;
return serialized(async () => {
// Primary: widget API. assertWorkableUrl + redirect:'error' together
// guarantee the final hostname stays in the allowlist (no SSRF via
// redirect). Retries transient failures; gives up early on a
// long-lived Retry-After so a Cloudflare-level block on this path
// falls through to the markdown feed instead of stalling the scan.
const apiUrl = assertWorkableUrl(widgetUrlFor(slug));
let payload = null;
try {
payload = await fetchWithRetry(ctx, () => ctx.fetchJson(apiUrl, {
redirect: 'error',
headers: { ...WORKABLE_HEADERS, referer },
}));
} catch {
payload = null; // fall through to the markdown feedView on GitHub (pinned to 9b17a8ac97)
Solutions
- Set careers_url: https://apply.workable.com/<slug> on the entry (find the slug in the company's Workable URL).
- If the company uses a branded domain, do not set provider: workable — let a different detection path handle it or drop the entry.
- Confirm the slug is alphanumeric / dash / underscore with no leading punctuation.
Example fix
# before - name: Acme provider: workable # after - name: Acme provider: workable careers_url: https://apply.workable.com/acme
Defensive patterns
Strategy: validation
Validate before calling
import { resolveWorkableSlug } from "./providers/workable.mjs";
// before scan
if (entry.provider === "workable") {
const slug = resolveWorkableSlug(entry);
if (!slug) { console.warn(`skip ${entry.name}: no workable slug in careers_url`); continue; }
} Type guard
const hasWorkableSlug = (e) => typeof resolveWorkableSlug(e) === "string";
Prevention
- Always pair provider: workable with a careers_url on apply.workable.com.
- Lint portals.yml entries for a resolvable slug before scanning.
When it happens
Trigger: A tracked_companies/job_boards entry with provider: workable whose careers_url is missing, is a branded careers domain (e.g. https://www.acme.com/careers), uses http, or whose slug contains characters outside [A-Za-z0-9_-] (leading dot/slash, spaces).
Common situations: User sets provider: workable on a company whose careers page is a custom domain; the entry relies on detection but has no careers_url; the slug has leading punctuation.
Related errors
- workday: cannot derive CXS endpoint for ${entry.name}
- smartrecruiters: cannot derive API URL for ${entry.name}
- softgarden: cannot resolve widget URL for ${entry.name}
- successfactors: cannot resolve origin for ${entry.name}
- teamtailor: cannot derive jobs.rss URL for ${fallbackCompany
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/90e7561b122ebf44.
Report an issue: GitHub.