decolua/9router · error · Error
Headroom URL must use http or https
Error message
Headroom URL must use http or https
What it means
getTargetBase resolves the Headroom upstream base URL from settings (headroomUrl or DEFAULT_HEADROOM_URL) and validates that its protocol is http: or https: before building a proxy target. Any other scheme makes the throw. This protects the catch-all proxy route from targets it cannot safely fetch.
Source
Thrown at src/app/api/headroom/proxy/[...path]/route.js:26
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailer",
"transfer-encoding",
"upgrade",
]);
const DASHBOARD_PREFIX = "/api/headroom/proxy";
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "::1"]);
async function getTargetBase() {
const settings = await getSettings();
const url = settings.headroomUrl || DEFAULT_HEADROOM_URL;
const target = new URL(url);
if (!["http:", "https:"].includes(target.protocol)) {
throw new Error("Headroom URL must use http or https");
}
return target;
}
function buildTargetUrl(base, path, search) {
const target = new URL(base);
target.pathname = `/${path.join("/")}`;
target.search = search;
return target;
}
function forwardedHeaders(request, target) {
const headers = new Headers(request.headers);
for (const header of headers.keys()) {
if (HOP_BY_HOP_HEADERS.has(header.toLowerCase())) headers.delete(header);
}
headers.delete("host");
// Never leak viewer credentials to a non-loopback Headroom hostView on GitHub (pinned to 90b52e06ff)
Solutions
- Open dashboard settings and set the Headroom URL to an http:// or https:// address, e.g. 'http://localhost:9000'.
- Correct settings.headroomUrl in the persisted settings store if edited directly.
- Ensure the URL includes the '//' after the scheme so it parses correctly.
Example fix
// before headroomUrl: "ws://localhost:9000" // after headroomUrl: "http://localhost:9000"
Defensive patterns
Strategy: validation
Validate before calling
const u = new URL(headroomUrl);
if (!["http:", "https:"].includes(u.protocol)) {
throw new Error("headroomUrl must start with http:// or https://");
} Type guard
const isHttpUrl = (v) => {
try { return ["http:", "https:"].includes(new URL(v).protocol); }
catch { return false; }
}; Try / catch
try {
await fetchProxy(path);
} catch (e) {
if (e.message === "Headroom URL must use http or https") {
console.error("Set headroomUrl to an http(s) URL in settings");
} else throw e;
} Prevention
- Store headroomUrl with a full scheme, e.g. http://localhost:9000
- Avoid bare host:port values that parse with unexpected schemes
- Validate settings after editing them via API or file
When it happens
Trigger: A request to /api/headroom/proxy/* when settings.headroomUrl is set to a URL with a non-http(s) scheme (e.g. 'ws://headroom:9930', 'file://...') or is otherwise malformed into an unexpected scheme by the URL parser.
Common situations: Operator stored a websocket or bare hostname (e.g. 'headroom.local:9000', which new URL() can mis-parse) in the headroom settings, or migrated config from another tool that used a different scheme.
Related errors
- Invalid host:port:user:pass format
- Unsupported format
- MITM router URL must use http or https
- xai discovery ${field} is invalid: ${err.message}
- Machine ID is required for Cursor API
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/a330da9f06d58ec0.
Report an issue: GitHub.