santifer/career-ops · warning · Error

comeet: invalid URL: ${redactToken(url)}

Error message

comeet: invalid URL: ${redactToken(url)}

What it means

Thrown by comeet's assertComeetUrl when the URL cannot be parsed by new URL() at all. Note this is a defense-in-depth re-check: through the public fetch() path it is effectively unreachable, because resolveApiUrl first runs isComeetApiUrl (which itself does new URL() in a try/catch and returns null on failure, surfacing as error 165 instead). assertComeetUrl is the second line of defence, reachable when it is invoked directly (e.g. a custom integration or unit test) with a malformed string.

Source

Thrown at providers/comeet.mjs:34

/** @param {unknown} raw */
function isComeetApiUrl(raw) {
  if (typeof raw !== 'string' || !raw) return false;
  let parsed;
  try {
    parsed = new URL(raw);
  } catch {
    return false;
  }
  return parsed.protocol === 'https:' && parsed.hostname === COMEET_API_HOST && parsed.pathname.startsWith('/careers-api/');
}

/** @param {string} url */
function assertComeetUrl(url) {
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error(`comeet: invalid URL: ${redactToken(url)}`);
  }
  if (parsed.protocol !== 'https:') throw new Error(`comeet: URL must use HTTPS: ${redactToken(url)}`);
  if (parsed.hostname !== COMEET_API_HOST)
    throw new Error(`comeet: untrusted hostname "${parsed.hostname}" — must be ${COMEET_API_HOST}`);
  if (!parsed.pathname.startsWith('/careers-api/'))
    throw new Error(`comeet: URL path must be the careers-api endpoint: ${redactToken(url)}`);
  return url;
}

// Redact the per-tenant ?token= so neither the (informational, possibly-logged)
// DetectHit url nor a thrown validation error carries the secret. Best-effort:
// falls back to a regex strip when the value can't be parsed as a URL.
function redactToken(url) {
  try {
    const parsed = new URL(url);
    if (parsed.searchParams.has('token')) parsed.searchParams.set('token', 'REDACTED');
    return parsed.href;
  } catch {

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. If calling assertComeetUrl directly, parse the value with new URL() yourself first and skip/handle non-URLs.
  2. For normal fetch() use, fix the entry config so resolveApiUrl returns a value (see error 165) — this branch will not fire otherwise.
  3. Confirm the two functions have not diverged: both should treat a non-URL string as a resolution failure (165), not an assertion failure (161).

Example fix

// before — direct call on raw input
assertComeetUrl(maybeUrl); // throws if maybeUrl is 'not a url'

// after — validate first
try { new URL(maybeUrl); } catch { /* not a URL, skip */ }
Defensive patterns

Strategy: validation

Validate before calling

// Through fetch() this is pre-empted by error 165. For a direct assertComeetUrl call:
function isParseableUrl(u) {
  try { new URL(u); return true; } catch { return false; }
}
if (!isParseableUrl(maybeUrl)) { /* skip, do not call assertComeetUrl */ }

Type guard

function isParseableUrl(u) {
  if (typeof u !== 'string' || !u) return false;
  try { new URL(u); return true; } catch { return false; }
}

Try / catch

// Only relevant for direct assertComeetUrl callers.
try { assertComeetUrl(url); }
catch (e) {
  if (/^comeet: invalid URL/.test(e.message)) { /* input wasn't a URL — skip */ }
  else throw e;
}

Prevention

When it happens

Trigger: assertComeetUrl is called directly with a value that is not a valid URL — empty string, a relative path, a string with illegal characters, or a non-URL scalar. The token is redacted in the message via redactToken so the thrown string never leaks the secret.

Common situations: Unit tests or a bespoke integration that calls assertComeetUrl on raw input; a future refactor that makes resolveApiUrl and assertComeetUrl source the URL differently. Normal scan/fetch use does not reach this branch.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/a2f04d3f19776134. Report an issue: GitHub.