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

  1. Set api: in the portals.yml entry to the full Comeet careers-api positions URL (https://www.comeet.co/careers-api/...).
  2. Verify the key name is exactly api: on the entry — compare against another working comeet entry in portals.yml.
  3. If the company is not actually on Comeet, switch the entry to the correct provider instead of supplying a fabricated URL.
  4. 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

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


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), so

View on GitHub (pinned to aac998c7ed)