santifer/career-ops · error
comeet: cannot derive API URL for
Error message
comeet: cannot derive API URL for ${entry.name} (set api: to the full careers-api positions URL) What it means
The Comeet provider's fetch calls resolveApiUrl(entry) to derive the careers-api positions URL from the portals.yml entry. When no URL can be derived (the entry lacks an api: field and no fallback source yields one), fetch throws this error instead of silently skipping, telling the operator exactly what to add. It is a configuration-completeness check, not a network failure.
Solutions
- Set api: in the portals.yml entry to the full Comeet careers-api positions URL (https://www.comeet.co/careers-api/...).
- Verify the key name is exactly api: on the entry — compare against another working comeet entry in portals.yml.
- If the company is not actually on Comeet, switch the entry to the correct provider instead of supplying a fabricated URL.
- Re-run the scan for just that entry to confirm resolveApiUrl now succeeds (the DetectHit url helper should return a redacted URL, not null).
Example fix
// portals.yml before - name: mycompany provider: comeet // after - name: mycompany provider: comeet api: https://www.comeet.co/careers-api/v2.1/company/mycompany/positions?token=XXXX
Defensive patterns
Strategy: validation
Validate before calling
if (entry.provider === 'comeet' && !entry.api) { throw new Error(`comeet entry '${entry.name}' is missing api:`); } Type guard
const hasComeetApi = (entry) => typeof entry.api === 'string' && entry.api.startsWith('https://www.comeet.co/careers-api/'); Try / catch
try {
await provider.fetch(entry, ctx);
} catch (err) {
if (err.message.includes('cannot derive API URL')) {
console.warn(`Skipping ${entry.name}: set api: to the full comeet careers-api URL`);
return null;
}
throw err;
} Prevention
- Include api: whenever you add a comeet provider entry to portals.yml
- Run verify-pipeline / a config check before scans to catch incomplete entries
- Copy the api URL template from an existing working comeet entry
- Watch for key typos (url vs api) when migrating entries between providers
When it happens
Trigger: Running a scan where a portals.yml entry is routed to the comeet provider but that entry has no api: value and resolveApiUrl returns null (no careers_url-derived API URL either).
Common situations: Adding a new company to portals.yml with provider: comeet but forgetting the api: key; typo-ing the key (e.g. url: instead of api:); an entry migrated from another ATS provider whose key shape does not match Comeet's expectations.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- comeet: URL path must be the careers-api endpoint
- consider: needs a 'consider_board' id in portals.yml
- csod: cannot resolve careersite URL for
- apify: entry has invalid field_map. Each of title, url…
- apify: entry missing 'actor' (e.g. misceres/indeed-scraper)
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/a5d25f84a0bea448.
Report an issue: GitHub.
Appendix: source
Thrown at providers/comeet.mjs:88
const parsed = Date.parse(value);
return Number.isNaN(parsed) ? undefined : parsed;
}
/** @type {Provider} */
export default {
id: 'comeet',
detect(entry) {
const apiUrl = resolveApiUrl(entry);
// The DetectHit url is informational (the framework may log it), so strip
// the secret ?token= before returning it — fetch() re-resolves the real
// URL from the entry, so redaction here is safe.
return apiUrl ? { url: redactToken(apiUrl) } : null;
},
async fetch(entry, ctx) {
const apiUrl = resolveApiUrl(entry);
if (!apiUrl) throw new Error(`comeet: cannot derive API URL for ${entry.name} (set api: to the full careers-api positions URL)`);
assertComeetUrl(apiUrl);
// redirect:'error' prevents SSRF via server-side redirects; combined with
// assertComeetUrl above it guarantees the final hostname stays www.comeet.co.
const json = await ctx.fetchJson(apiUrl, { redirect: 'error' });
return parseComeetResponse(json, entry.name);
},
};
/**
* Parse a Comeet careers-api positions response. Exported for unit tests.
*
* Comeet returns a top-level ARRAY of position objects:
* [{ name, location: { name, is_remote }, url_active_page,
* url_comeet_hosted_page, time_updated, ... }]
*
* - url: prefer `url_active_page` (the tenant's live careers page), fall back to
* `url_comeet_hosted_page` (the Comeet-hosted page). Both are public, display-
* only URLs (recorded in the pipeline/history, never server-fetched here), soView on GitHub (pinned to aac998c7ed)