headroomlabs-ai/headroom · error · Error

Headroom OpenCode transport shim loaded without HEADROOM_OPE

Error message

Headroom OpenCode transport shim loaded without HEADROOM_OPENCODE_TRANSPORT_PROXY_URL

What it means

Same guard as the built shim, but in the source variant plugins/opencode/src/hook-shim.ts used for wheel (pip) installs: it inlines the transport import and still requires HEADROOM_OPENCODE_TRANSPORT_PROXY_URL at module load. The comment history shows this path previously crashed children with ERR_MODULE_NOT_FOUND and then silently disabled routing; now it fails loudly when the env var is missing. Throwing at import time makes misconfiguration visible instead of silently unrouted traffic.

Source

Thrown at plugins/opencode/src/hook-shim.ts:21

// at headroom/providers/opencode/hook-shim/handler.js.
//
// transport.ts wraps `fetch`/`http`/`https` in the plugin's own process, but a
// spawned Node child (an `npx` MCP server, `tokensave serve`, ...) is a fresh
// process, so its traffic is only routed if this loader runs at that child's
// startup via NODE_OPTIONS=--import. `shimImportSpecifier()` in transport.ts
// resolves `../hook-shim/handler.js` next to the loaded entry, which is this
// file in a wheel install.
//
// The checkout uses plugins/opencode/hook-shim/handler.js instead, which imports
// the non-bundled `../dist/index.js`; pip installs have no node_modules, so this
// variant inlines the transport. Without it shipped, the loader path did not
// exist, so child-process routing was silently disabled for wheel installs
// (before #2806 it crashed every Node child with ERR_MODULE_NOT_FOUND) (#2850).
import { installHeadroomTransport } from "./transport.js";

const proxyUrl = process.env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL;
if (!proxyUrl) {
  throw new Error(
    "Headroom OpenCode transport shim loaded without HEADROOM_OPENCODE_TRANSPORT_PROXY_URL",
  );
}

installHeadroomTransport({ proxyUrl });

View on GitHub (pinned to 322425c43b)

Solutions

  1. Export the variable in the shell/profile that launches OpenCode: export HEADROOM_OPENCODE_TRANSPORT_PROXY_URL=http://127.0.0.1:8787
  2. Put it in the OpenCODE project/user config env section or .env mechanism your launcher honors so all children inherit it
  3. If some sessions intentionally run without the proxy, disable the hook there instead of loading the shim without the variable

Example fix

# before: pip-installed plugin loaded without the var
pip install headroom-ai && opencode  # shim throws on import

# after
pip install headroom-ai
export HEADROOM_OPENCODE_TRANSPORT_PROXY_URL=http://127.0.0.1:8787
opencode
Defensive patterns

Strategy: validation

Validate before calling

// Validate env before the hook can load the source shim (pip/wheel installs)
if (!process.env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL) {
  console.error(
    "Skipping Headroom OpenCode transport: HEADROOM_OPENCODE_TRANSPORT_PROXY_URL is not set"
  );
} else {
  await import("./hook-shim.js");
}

Type guard

function hasTransportEnv(env: Record<string, string | undefined>): boolean {
  return Boolean(env.HEADROOM_OPENCODE_TRANSPORT_PROXY_URL);
}

Prevention

When it happens

Trigger: Importing plugins/opencode/src/hook-shim.ts (pip/wheel install of the OpenCode plugin) without HEADROOM_OPENCODE_TRANSPORT_PROXY_URL set in that process's environment.

Common situations: pip-installed plugin loaded by OpenCode hooks in a shell where the variable was never exported; CI runners with a minimal env; switching from npm to pip install of headroom and forgetting the env setup step; hook config enabled for all projects but the var only set in one shell profile.

Related errors


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