santifer/career-ops · error
breezy: URL must use HTTPS
Error message
breezy: URL must use HTTPS: ${url} What it means
assertBreezyUrl throws this when the URL parses but its protocol is not 'https:'. The provider only talks to Breezy tenant boards over TLS, both to protect the scrape and as part of the SSRF defence (an http: origin could be intercepted or redirected). Any http:// or other-scheme URL is rejected before fetching.
Solutions
- Change the scheme in the portals.yml entry to https:// (e.g. 'https://acme.breezy.hr').
- Confirm the tenant board actually serves HTTPS — all Breezy HR boards do, so plain http is always a config mistake.
- If the URL comes from code, hardcode the 'https://' prefix when composing the origin rather than accepting caller input.
Example fix
// before
const apiUrl = `http://${tenant}.breezy.hr/json`;
// after
const apiUrl = `https://${tenant}.breezy.hr/json`; Defensive patterns
Strategy: validation
Validate before calling
function isHttpsUrl(url) {
try { return new URL(url).protocol === 'https:'; } catch { return false; }
}
if (!isHttpsUrl(entry.careers_url)) throw new Error(`config: careers_url must be https: ${entry.careers_url}`); Type guard
function isHttpsProtocol(url) { try { return new URL(url).protocol === 'https:'; } catch { return false; } } Try / catch
try {
await provider.fetch(entry, ctx);
} catch (err) {
if (String(err.message).startsWith('breezy: URL must use HTTPS')) {
console.warn(`Upgrading ${entry.name} to https and retrying once`);
return provider.fetch({ ...entry, careers_url: entry.careers_url.replace(/^http:/, 'https:') }, ctx);
}
throw err;
} Prevention
- Normalize http:// to https:// once at config-load time instead of per-fetch.
- Never accept caller-supplied schemes; compose URLs from a hardcoded https:// prefix.
- Add a startup check that rejects any non-https careers_url in portals.yml.
When it happens
Trigger: A portals.yml entry configured with 'http://acme.breezy.hr/json' or an api: field using a non-https scheme (ftp:, //protocol-relative resolved oddly, etc.) reaches assertBreezyUrl via provider fetch().
Common situations: Copying a URL from a browser that downgraded to http; writing 'http://' by habit in local config; a config migration that stripped the 's'; protocol-relative '//acme.breezy.hr' strings which fail earlier or resolve with page 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
- builtin: URL must use HTTPS
- careerviet: URL must use HTTPS
- comeet: URL must use HTTPS
- gem: URL must use HTTPS
- arbeitnow: URL must use HTTPS
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/385c711ce66f8654.
Report an issue: GitHub.
Appendix: source
Thrown at providers/breezy.mjs:26
// approach as the recruitee / bamboohr providers).
//
// Breezy boards expose every published position as a public JSON array at
// `<tenant>.breezy.hr/json` — title, absolute url, location, and a published
// date, all in the list payload at zero token cost (no per-job request, so the
// scanner stays zero-token). Breezy's authenticated REST API (api.breezy.hr) is
// intentionally NOT used; only the public board feed.
const BREEZY_HOST_RE = /^[a-z0-9][a-z0-9-]*\.breezy\.hr$/;
/** @param {string} url */
function assertBreezyUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`breezy: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`breezy: URL must use HTTPS: ${url}`);
if (!BREEZY_HOST_RE.test(parsed.hostname)) {
throw new Error(`breezy: untrusted hostname "${parsed.hostname}" — must match <tenant>.breezy.hr`);
}
return url;
}
/**
* Resolve the tenant origin (`https://<tenant>.breezy.hr`) from an entry.
* Honours an explicit `api:` URL, else parses `careers_url`.
* @param {import('./_types.js').PortalEntry} entry
* @returns {string | null}
*/
function resolveOrigin(entry) {
const rawApi = typeof entry.api === 'string' ? entry.api : '';
const rawCareers = typeof entry.careers_url === 'string' ? entry.careers_url : '';
const raw = (rawApi || rawCareers).trim();
if (!raw) return null;
let parsed;View on GitHub (pinned to aac998c7ed)