santifer/career-ops · error
builtin: URL must use HTTPS
Error message
builtin: URL must use HTTPS: ${url} What it means
assertHost in the builtin provider throws this when the URL parses but its protocol is not 'https:'. The provider only fetches Built In city sites over TLS as part of its SSRF defence; any http:// or other-scheme URL is rejected before the request is made.
Solutions
- Change the scheme to https:// in the config value or URL-composition code.
- Remember resolveHost expects a bare host — supply 'www.builtinseattle.com' and let the provider add the https scheme itself.
- Update any http:// test fixtures to https:// so they pass the guard.
Example fix
// before host: http://www.builtinchicago.org // after host: www.builtinchicago.org
Defensive patterns
Strategy: validation
Validate before calling
function isHttpsUrl(url) {
try { return new URL(url).protocol === 'https:'; } catch { return false; }
}
if (!isHttpsUrl(url)) throw new Error(`builtin requests must use https: ${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('builtin: URL must use HTTPS')) {
console.warn(`Upgrading ${entry.name} URL to https and retrying once`);
return provider.fetch(entry, ctx, /* httpsOnly */ true);
}
throw err;
} Prevention
- Let the provider own the scheme: configure bare hosts, not full URLs.
- Normalize http:// to https:// once at config load.
- Use https:// in test fixtures so they behave like production.
When it happens
Trigger: A request URL reaching assertHost with scheme http:, e.g. built from a config value 'http://www.builtinseattle.com' or an internally composed URL where the https prefix was mistyped or stripped.
Common situations: Hand-written config using http:// by habit; a rewrite/migration that dropped the 's'; a proxy-related override pointing at an http endpoint; test fixtures that use http and then run through the real guard.
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
- breezy: 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/56db369c2160365a.
Report an issue: GitHub.
Appendix: source
Thrown at providers/builtin.mjs:171
}
/**
* SSRF guard — every request URL passes through here before it is fetched. The
* host comes from config, so this is the only thing standing between a
* portals entry and an arbitrary fetch target. It checks the RESOLVED host
* against the allowlist again rather than trusting the caller.
*
* @param {string} url
* @returns {string}
*/
function assertHost(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
throw new Error(`builtin: invalid URL: ${url}`);
}
if (parsed.protocol !== 'https:') throw new Error(`builtin: URL must use HTTPS: ${url}`);
const host = parsed.hostname.toLowerCase();
if (HOSTS.get(host) !== host) {
throw new Error(`builtin: untrusted hostname "${parsed.hostname}" — must be one of ${[...new Set(HOSTS.values())].join(', ')}`);
}
return url;
}
/** @param {string} s */
function stripTags(s) {
return decodeEntities(String(s).replace(/<[^>]*>/g, ' ')).replace(/\s+/g, ' ').trim();
}
/**
* Text of the first element following an icon marker inside a card.
* Anchoring on the icon class (rather than on field order) is what keeps this
* readable when Built In reshuffles the card layout.
*
* @param {string} seg card HTMLView on GitHub (pinned to aac998c7ed)