headroomlabs-ai/headroom · error · Error
Remote Headroom proxy not reachable at ${explicitUrl}. Ensur
Error message
Remote Headroom proxy not reachable at ${explicitUrl}. Ensure the proxy is running at that address. What it means
A non-local proxyUrl (hostname other than 127.0.0.1/localhost) was configured, the probe could not reach it, and the manager refuses to auto-start anything for remote URLs by design — auto-start only ever spawns a local subprocess. The error tells you the remote proxy must be running and reachable before OpenClaw connects.
Source
Thrown at plugins/openclaw/src/proxy-manager.ts:108
if (probe.reachable && probe.isHeadroom) {
this.proxyUrl = url;
this.logger.info(`Headroom proxy already running at ${url}`);
return url;
}
}
if (explicitUrl) {
const explicitProbe = probeByUrl.get(explicitUrl);
if (explicitProbe?.reachable && !explicitProbe.isHeadroom) {
throw new Error(
`Service reachable at ${explicitUrl}, but it does not appear to be a Headroom proxy (${explicitProbe.reason ?? "unknown service"}).`,
);
}
}
// Remote URLs are connect-only — never auto-start a subprocess for them
if (explicitUrl && !isLocalProxyUrl(explicitUrl)) {
throw new Error(
`Remote Headroom proxy not reachable at ${explicitUrl}. Ensure the proxy is running at that address.`,
);
}
// Auto-start is only available for local proxies
if (this.config.autoStart === true) {
const startupUrl = explicitUrl ?? defaultCandidates[0];
const startupProbe = probeByUrl.get(startupUrl);
if (startupProbe?.reachable && !startupProbe.isHeadroom) {
throw new Error(
`Cannot auto-start Headroom at ${startupUrl}: port is in use by a non-Headroom service (${startupProbe.reason ?? "unknown service"}).`,
);
}
this.logger.info(
`No Headroom proxy detected${explicitUrl ? ` at ${startupUrl}` : " on default local endpoints"}; attempting to auto-start...`,
);
await this.startHeadroomProxy(startupUrl, port);View on GitHub (pinned to 322425c43b)
Solutions
- Start (or restart) the Headroom proxy on the remote host and confirm it binds an address reachable from the client (not just remote-loopback): headroom proxy --host 0.0.0.0 --port 8787
- Verify reachability from the client machine: curl http://<host>:8787 — fix DNS, firewall, or VPN issues it reveals
- If the proxy is actually local, use http://127.0.0.1:<port> so the manager can auto-start it
- If the remote service starts slowly, delay client startup until it is up (health check before constructing the manager)
Example fix
# on the remote host — before: bound to loopback only headroom proxy --host 127.0.0.1 --port 8787 # after: bind so clients can reach it headroom proxy --host 0.0.0.0 --port 8787
Defensive patterns
Strategy: validation
Validate before calling
async function remoteProxyUp(url: string, timeoutMs = 3000): Promise<boolean> {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), timeoutMs);
try {
await fetch(url, { signal: ctrl.signal });
return true; // reachable at HTTP level; identity checked by the manager
} catch {
return false;
} finally {
clearTimeout(t);
}
}
const url = "http://proxy.internal:8787";
if (!await remoteProxyUp(url)) {
throw new Error(`Remote proxy ${url} not up yet; wait for it before starting the client`); Type guard
import { isLocalProxyUrl } from "./proxy-manager.js";
function requiresRunningProxy(proxyUrl: string): boolean {
// Remote URLs are connect-only: never expect auto-start for them
return !isLocalProxyUrl(proxyUrl);
} Try / catch
try {
await manager.resolveProxyUrl();
} catch (e) {
if (e instanceof Error && e.message.includes("Remote Headroom proxy not reachable")) {
// infrastructure issue: surface to ops, do not retry in-process
throw new Error(`Headroom proxy host is down or unreachable — check the remote service`);
}
throw e;
} Prevention
- Add the remote proxy URL to your orchestration's dependency/health checks so the client starts only when it is up
- Document that remote URLs never auto-start — startup ordering is the deployer's responsibility
- Use a stable internal DNS name and monitor it, so a moved/rehosted proxy fails loudly in monitoring first
When it happens
Trigger: Configuring proxyUrl like http://proxy.internal:8787 or http://10.0.0.5:8787 when nothing is listening there, when a firewall blocks it, when the hostname does not resolve, or when the remote Headroom process is not started yet.
Common situations: Shared/team Headroom proxy on a remote host that is down; Docker/K8s service name misspelled or not yet up when the client starts; VPN or network policy blocking the port; remote Headroom bound to 127.0.0.1 instead of 0.0.0.0.
Related errors
- Headroom proxy startup is disabled
- Service reachable at ${explicitUrl}, but it does not appear
- Headroom proxy not reachable at ${explicitUrl}. Ensure the p
- Headroom proxy not detected on default endpoints (${defaultC
- proxyPort must be an integer between 1 and 65535
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/db3820f7541d0820.
Report an issue: GitHub.