santifer/career-ops · error
bamboohr: cannot derive API URL for
Error message
bamboohr: cannot derive API URL for ${entry.name} What it means
BambooHR's fetch() calls resolveOrigin(entry) to get the tenant origin `https://<tenant>.bamboohr.com`; if it returns null the provider cannot build the `/careers/list` endpoint and throws. Like Ashby's equivalent, it refuses to request anything when config is insufficient.
Solutions
- Add/set the entry's origin or api field to `https://<tenant>.bamboohr.com`.
- Fix the tenant subdomain so the hostname matches `<tenant>.bamboohr.com` (this also makes resolveOrigin succeed).
- Verify the company actually hosts jobs on BambooHR; otherwise move the entry to the right provider.
- Validate entries at load time: reject entries where resolveOrigin(entry) is null with a clear config warning.
Example fix
// before
{ name: 'ExampleCo', careers_url: 'https://exampleco.com/careers' }
// fetch throws: cannot derive API URL
// after
{ name: 'ExampleCo', api: 'https://exampleco.bamboohr.com/careers/list' } Defensive patterns
Strategy: fallback
Validate before calling
function hasBambooOrigin(entry) {
return resolveOrigin(entry) != null;
} Type guard
function isBambooReadyEntry(entry) {
return typeof entry?.name === 'string' && typeof resolveOrigin(entry) === 'string';
} Try / catch
try {
return await bamboohrProvider.fetch(entry, ctx);
} catch (err) {
if (/cannot derive API URL/.test(err.message)) {
console.warn(`Entry ${entry.name}: missing <tenant>.bamboohr.com origin in config`);
return null;
}
throw err;
} Prevention
- Populate the api/origin field with `https://<tenant>.bamboohr.com` for every BambooHR entry.
- Verify the tenant subdomain spelling — resolveOrigin fails on any host-pattern mismatch.
- Confirm the company genuinely hosts jobs on BambooHR before assigning it to this provider.
- Validate origins for all entries at config load and surface failures early.
When it happens
Trigger: Calling fetch(entry) with an entry lacking a usable origin — no api/careers URL matching the BambooHR tenant pattern, or a blank tenant field — so resolveOrigin returns null.
Common situations: portals.yml entry where only the corporate site is listed, tenant subdomain typo making the host pattern fail, or entries migrated from another provider without a BambooHR origin field.
Understand the failure class
Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.
Related errors
- ashby: cannot derive API URL for
- arbeitnow: invalid URL
- arbeitsagentur: entry
- avature: cannot resolve origin for
- bamboohr: invalid URL
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/a06a50c7ba0ead2e.
Report an issue: GitHub.
Appendix: source
Thrown at providers/bamboohr.mjs:67
return null;
}
if (parsed.protocol !== 'https:') return null;
if (!BAMBOOHR_HOST_RE.test(parsed.hostname)) return null;
return `https://${parsed.hostname}`;
}
/** @type {Provider} */
export default {
id: 'bamboohr',
detect(entry) {
const origin = resolveOrigin(entry);
return origin ? { url: `${origin}/careers/list` } : null;
},
async fetch(entry, ctx) {
const origin = resolveOrigin(entry);
if (!origin) throw new Error(`bamboohr: cannot derive API URL for ${entry.name}`);
const apiUrl = `${origin}/careers/list`;
assertBambooHRUrl(apiUrl);
// redirect:'error' + the host check above keep the final hostname pinned to
// the tenant — a server-side redirect can't bounce us off-domain (SSRF).
const json = /** @type {any} */ (await ctx.fetchJson(apiUrl, { redirect: 'error' }));
return parseBambooHRResponse(json, entry.name, origin);
},
};
/**
* Parse a BambooHR `/careers/list` response. Exported for unit tests.
*
* BambooHR returns:
* { meta: {...}, result: [{ id, jobOpeningName,
* location: { city?, state? }, isRemote?, employmentStatusLabel? }] }
*
* - url: built as `<origin>/careers/<id>` — matches the public
* `jobOpeningShareUrl`. Rows without a non-empty `id` are dropped (no stableView on GitHub (pinned to aac998c7ed)