santifer/career-ops · error

consider: needs an https careers_url on a public host

Error message

consider: ${entry.name} needs an https careers_url on a public host

What it means

The Consider provider requires each portals.yml entry to have a careers_url that resolves to an HTTPS origin on a public host; resolveOrigin(entry) returns null otherwise, and fetch throws this error. Consider's CSRF-handshake + POST flow must target a reachable public https endpoint, so private/relative/non-https origins are rejected up front. The error names the offending entry so the bad config line is easy to find.

Solutions

  1. Add or fix careers_url on the entry so it is a full https:// URL on a public host (e.g. https://jobs.company.com).
  2. Confirm the scheme is https (http:// is rejected) and the host is public — no localhost, 127.0.0.1, or private ranges.
  3. Verify consider_board is set too, since fixing the origin alone leads straight to the next error about the missing board id.
  4. Test the origin resolves with a quick `new URL(entry.careers_url)` and protocol/hostname check before re-running the scan.

Example fix

// before
- name: mycompany
  provider: consider
  consider_board: abc123
// after
- name: mycompany
  provider: consider
  careers_url: https://jobs.mycompany.com
  consider_board: abc123
Defensive patterns

Strategy: validation

Validate before calling

function isPublicHttpsOrigin(u) { try { const p = new URL(u); return p.protocol === 'https:' && !['localhost','127.0.0.1'].includes(p.hostname) && !p.hostname.endsWith('.local') && !/^10\./.test(p.hostname) && !/^192\.168\./.test(p.hostname); } catch { return false; } }
if (entry.provider === 'consider' && !isPublicHttpsOrigin(entry.careers_url)) throw new Error(`consider entry '${entry.name}' needs a public https careers_url`);

Type guard

const hasPublicHttpsOrigin = (u) => { try { const p = new URL(u); return p.protocol === 'https:' && p.hostname !== 'localhost' && p.hostname.includes('.'); } catch { return false; } };

Prevention

When it happens

Trigger: Scanning an entry with provider consider whose careers_url is missing, is http:// instead of https://, is localhost/private-IP, or is otherwise unresolvable to a public https origin.

Common situations: Copy-pasting an internal staging careers URL (localhost or intranet host) into portals.yml; omitting careers_url entirely while setting consider_board; a typo making the URL unparseable so resolveOrigin returns null.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/fa4d28b05f4b0c5a. Report an issue: GitHub.

Appendix: source

Thrown at providers/consider.mjs:150

  }
  if (Array.isArray(job.normalizedLocations) && job.normalizedLocations.length) {
    return job.normalizedLocations.map(l => l?.label || l?.value).filter(Boolean).join(', ');
  }
  return job.remote ? 'Remote' : '';
}

/** @type {Provider} */
export default {
  id: 'consider',

  detect(entry) {
    const origin = resolveOrigin(entry);
    return entry.consider_board && origin ? { url: origin + ENDPOINT_PATH } : null;
  },

  async fetch(entry, ctx) {
    const origin = resolveOrigin(entry);
    if (!origin) throw new Error(`consider: ${entry.name} needs an https careers_url on a public host`);
    if (!entry.consider_board) throw new Error(`consider: ${entry.name} needs a 'consider_board' id in portals.yml`);
    const size = Number.isInteger(entry.consider_size) && entry.consider_size > 0 ? entry.consider_size : DEFAULT_SIZE;

    // Perform the CSRF handshake before the POST. ctx._acquireHandshake is a
    // test seam: set it to a stub in unit tests so no real network call is made.
    const { cookie, csrfToken } = await (
      typeof ctx._acquireHandshake === 'function'
        ? ctx._acquireHandshake(origin)
        : acquireCsrfHandshake(origin)
    );

    const csrfHeaders = {};
    if (cookie) csrfHeaders.cookie = cookie;
    if (csrfToken) csrfHeaders['x-csrf-token'] = csrfToken;

    const json = await ctx.fetchJson(origin + ENDPOINT_PATH, {
      method: 'POST',
      // redirect:'error' so a 3xx from the (config-driven) board host can't be

View on GitHub (pinned to aac998c7ed)