santifer/career-ops · error · Error
ashby: cannot derive API URL for ${entry.name}
Error message
ashby: cannot derive API URL for ${entry.name} What it means
ashby's `fetch` calls `resolveApiUrl(entry)` to find the posting-API URL. If it returns a falsy value (no `entry.api` and no derivable board URL), `fetch` throws naming the entry. This is a hard config error — there is no endpoint to hit.
Source
Thrown at providers/ashby.mjs:162
return [...new Set(parts)].join(' · ');
}
/** @type {Provider} */
export default {
id: 'ashby',
detect(entry) {
try {
const apiUrl = resolveApiUrl(entry);
return apiUrl ? { url: apiUrl } : null;
} catch {
return null;
}
},
async fetch(entry, ctx) {
const apiUrl = resolveApiUrl(entry);
if (!apiUrl) throw new Error(`ashby: cannot derive API URL for ${entry.name}`);
assertAshbyUrl(apiUrl);
let lastErr;
for (let attempt = 0; attempt <= ASHBY_RETRIES; attempt++) {
if (attempt > 0) {
// exponential backoff + jitter — spaces out retries to dodge Ashby rate-limiting
const backoff = 1000 * 2 ** (attempt - 1) + Math.floor(Math.random() * 500);
await sleep(backoff, ctx);
}
try {
const json = /** @type {any} */ (await ctx.fetchJson(apiUrl, { timeoutMs: ASHBY_TIMEOUT_MS, redirect: 'error' }));
const jobs = Array.isArray(json?.jobs) ? json.jobs : [];
return jobs.map(/** @param {any} j */ (j) => ({
title: j.title || '',
url: j.jobUrl || '',
company: entry.name,
location: formatLocation(j),
salary: parseCompensation(j),
postedAt: toEpochMs(j.publishedAt),View on GitHub (pinned to 9b17a8ac97)
Solutions
- Add an `api:` field pointing to `https://api.ashbyhq.com/posting-api?compId=<tenant>`.
- Confirm the provider actually applies to this entry — if it isn't an Ashby board, switch `provider:`.
- Use `detect()` (or the scanner's detection pass) before calling `fetch` so unconfigured entries are skipped cleanly.
Example fix
# before - name: Acme provider: ashby careers_url: https://careers.acme.com/ # after — explicit api: pins the board - name: Acme provider: ashby careers_url: https://careers.acme.com/ api: https://api.ashbyhq.com/posting-api?compId=acme
Defensive patterns
Strategy: type-guard
Validate before calling
// Use detect() before fetch so unconfigured entries are skipped, not thrown
const detected = provider.detect(entry);
if (!detected) {
console.warn(`ashby: skipping ${entry.name} — no API URL derivable (add api: or careers_url)`);
continue;
}
const jobs = await provider.fetch(entry, ctx); Type guard
/** @param {any} e */
function hasAshbyApiConfig(e) {
return typeof e?.api === 'string' && e.api.length > 0;
} Try / catch
try {
const apiUrl = resolveApiUrl(entry);
if (!apiUrl) throw new Error(`ashby: cannot derive API URL for ${entry.name}`);
// ...fetch
} catch (err) {
if (/cannot derive API URL/.test(err.message)) {
console.warn(`skipping ${entry.name}: ${err.message}`); // config gap, not a crash
return [];
}
throw err;
} Prevention
- Always call `detect()` before `fetch()` so missing config is skipped gracefully.
- Require an explicit `api:` field in ashby entries during config validation.
- Surface a config report listing entries where detect() returned null.
When it happens
Trigger: `resolveApiUrl(entry)` returns null/undefined: the entry has no `api:` field and no other field from which the Ashby board URL can be derived. Thrown at the top of `fetch` before any network call. Note `detect()` catches the same failure and returns null (skipping the provider) — this throw only fires if `fetch` is invoked directly.
Common situations: An entry lists ashby as its provider but omits the `api:` field; a YAML indentation error separated `api` from its entry; or the entry was created from a template that left the API URL blank.
Related errors
- Unsupported profile photo style: ${style} (expected rounded,
- Malformed benchmarks file at ${path}: expected a top-level "
- gmail: invalid days_back "${ctx?.settings?.days_back}" (must
- arbeitsagentur: entry "${entry.name || '(unnamed)'}" has no
- ashby: invalid URL: ${url}
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/6fe850c64346060b.
Report an issue: GitHub.