headroomlabs-ai/headroom · error · Error

Headroom proxy startup is disabled

Error message

Headroom proxy startup is disabled

What it means

ensureProxyUrl() on the OpenClaw engine requires a Headroom proxy, but no proxy URL has been resolved yet and auto-start did not produce a startup promise. ensureProxyStarted() only creates proxyStartupPromise when auto-start is enabled/configured; when it is disabled, the method throws this error immediately. It means the caller wants proxy routing without having provided a running proxy or enabled the engine to start one.

Source

Thrown at plugins/openclaw/src/engine.ts:337

    // a missing proxy cannot become a process-level unhandled rejection.
    void this.proxyStartupPromise.catch(() => {});
  }

  onProxyReady(listener: (proxyUrl: string) => void | Promise<void>): () => void {
    this.proxyReadyListeners.add(listener);
    return () => {
      this.proxyReadyListeners.delete(listener);
    };
  }

  async ensureProxyUrl(): Promise<string> {
    if (this.proxyUrl) {
      return this.proxyUrl;
    }

    this.ensureProxyStarted();
    if (!this.proxyStartupPromise) {
      throw new Error("Headroom proxy startup is disabled");
    }
    return this.proxyStartupPromise;
  }

  private async notifyProxyReady(proxyUrl: string): Promise<void> {
    for (const listener of this.proxyReadyListeners) {
      try {
        await listener(proxyUrl);
      } catch (error) {
        this.logger.warn(`Headroom proxy ready listener failed: ${error}`);
      }
    }
  }
}

View on GitHub (pinned to 322425c43b)

Solutions

  1. Enable proxy auto-start in the engine configuration so ensureProxyStarted() creates a startup promise
  2. Or point the engine at an already-running proxy (set proxyUrl in config / resolve it via the proxy manager first) so ensureProxyUrl returns the cached URL
  3. Or start the Headroom proxy out-of-band and register its URL with the engine before any code path calls ensureProxyUrl()

Example fix

// before: autoStart not enabled, no proxyUrl set
await engine.ensureProxyUrl(); // throws

// after: either enable autoStart
engine.configure({ proxy: { autoStart: true } });
await engine.ensureProxyUrl();

// or supply a running proxy explicitly
engine.configure({ proxy: { proxyUrl: "http://127.0.0.1:8787" } });
Defensive patterns

Strategy: validation

Validate before calling

// Call before any code path can hit ensureProxyUrl()
function canEnsureProxy(engine: { proxyUrl?: string }, config: { autoStart?: boolean }): boolean {
  return Boolean(engine.proxyUrl) || config.autoStart === true;
}

if (!canEnsureProxy(engine, engineConfig)) {
  throw new Error("Configure proxyUrl or enable autoStart before requesting the proxy");
}

Type guard

function isProxyReady(engine: { proxyUrl?: string }): engine is { proxyUrl: string } {
  return typeof engine.proxyUrl === "string" && engine.proxyUrl.length > 0;
}

Try / catch

try {
  const url = await engine.ensureProxyUrl();
} catch (e) {
  if (e instanceof Error && e.message.includes("startup is disabled")) {
    // config gap: enable autoStart or provide a running proxy URL
    throw new Error("Proxy required but auto-start disabled: set proxyUrl or autoStart");
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling engine.ensureProxyUrl() when engine.proxyUrl is unset (no proxy previously resolved) and the engine's configuration has proxy start/autoStart disabled, so ensureProxyStarted() leaves proxyStartupPromise undefined.

Common situations: Integrating OpenClaw with an externally managed Headroom proxy but forgetting to configure its URL; disabling autoStart in a locked-down environment and then calling an API that transparently needs the proxy; ordering bug where ensureProxyUrl is called before the config that enables startup is applied.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/d7e72fbd3a03fb7b. Report an issue: GitHub.