santifer/career-ops · error

collage: URL must use HTTPS

Error message

collage: URL must use HTTPS: ${url}

What it means

assertCollageApiUrl requires every explicitly configured Collage API URL to use the https: protocol; the provider refuses to issue plaintext HTTP requests to the API host. This error fires when the parsed URL is valid but its protocol is http: (or anything other than https:).

Solutions

  1. Change the scheme to https:// in the `api:` field of the portals.yml entry
  2. Re-run the scan to confirm the entry is picked up
  3. Never downgrade to http — Collage's API host serves HTTPS only

Example fix

# before (portals.yml)
api: http://api.collage.co/v1/positions/acme
# after
api: https://api.collage.co/v1/positions/acme
Defensive patterns

Strategy: validation

Validate before calling

// Ensure HTTPS before handing the URL to the provider
function isHttpsUrl(v) {
  try { return new URL(v).protocol === 'https:'; } catch { return false; }
}
if (!isHttpsUrl(entry.api)) throw new Error(`${entry.name}: api must use https://`);

Type guard

function isHttpsCollageApi(v) {
  try { const u = new URL(v); return u.protocol === 'https:' && u.hostname === 'api.collage.co'; }
  catch { return false; }
}

Try / catch

try {
  const jobs = await collageProvider.fetch(entry, ctx);
} catch (err) {
  if (String(err.message).includes('URL must use HTTPS')) {
    console.error(`Upgrade ${entry.api} to https:// in portals.yml`);
  } else { throw err; }
}

Prevention

When it happens

Trigger: A portals.yml entry has `api: http://api.collage.co/v1/positions/<site>` — http scheme instead of https. Any other scheme (ftp:, ws:) would hit the same check.

Common situations: Typing http:// out of habit; migrating an entry from a local dev mock URL; a config generator that templates scheme://host with the wrong scheme.

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/1b346f58bb959cb0. Report an issue: GitHub.

Appendix: source

Thrown at providers/collage.mjs:17

// @ts-check
/** @typedef {import('./_types.js').Provider} Provider */

// Collage HR public job-site API.  A job-site address is an explicit tenant
// identifier, not a company-name slug we should guess.  Entries may provide
// the exact API URL or a public Collage careers URL from which the final path
// segment is read.

const API_ORIGIN = 'https://api.collage.co';
const COLLAGE_API_HOST = 'api.collage.co';
const COLLAGE_SITE_HOST_RE = /^secure\.collage\.co$/;

/** @param {string} url */
function assertCollageApiUrl(url) {
  let parsed;
  try { parsed = new URL(url); } catch { throw new Error(`collage: invalid URL: ${url}`); }
  if (parsed.protocol !== 'https:') throw new Error(`collage: URL must use HTTPS: ${url}`);
  if (parsed.hostname !== COLLAGE_API_HOST) {
    throw new Error(`collage: untrusted hostname "${parsed.hostname}" — must be ${COLLAGE_API_HOST}`);
  }
  if (!/^\/v1\/positions\/[^/?#]+$/.test(parsed.pathname)) {
    throw new Error(`collage: API URL must be /v1/positions/<job-site-address>: ${url}`);
  }
  return url;
}

/** @param {import('./_types.js').PortalEntry} entry */
function resolveApiUrl(entry) {
  const explicit = typeof entry.api === 'string' ? entry.api.trim() : '';
  if (explicit) return assertCollageApiUrl(explicit);

  const raw = typeof entry.careers_url === 'string' ? entry.careers_url.trim() : '';
  if (!raw) return null;
  let parsed;
  try { parsed = new URL(raw); } catch { return null; }

View on GitHub (pinned to aac998c7ed)