JuliusBrussee/caveman · error · AgentMcpHTTPError

cave_auth_required

cave_auth_required

Error message

Not logged in. Run `caveman login` or set CAVE_TOKEN for headless use.

What it means

agentMcpRequest() performs authenticated API calls against the Cave backend. When the local config has no stored token, it throws an AgentMcpHTTPError with code `cave_auth_required` (HTTP 401) telling the user to run `caveman login` or set CAVE_TOKEN.

Solutions

  1. Run `caveman login` to store a token
  2. Set the CAVE_TOKEN environment variable in the shell/CI environment
  3. Verify the config file still contains the token (`caveman whoami` or inspect config)
  4. Re-authenticate if the token was revoked or expired

Example fix

// before (CI step)
- run: caveman agent sync
// after
- run: |
    export CAVE_TOKEN=${{ secrets.CAVE_TOKEN }}
    caveman agent sync
Defensive patterns

Strategy: try-catch

Validate before calling

const cfg = await config();
if (!cfg.token && !process.env.CAVE_TOKEN) { console.error('Not authenticated: run `caveman login` or set CAVE_TOKEN'); process.exit(1); }

Type guard

const isAuthError = (e: unknown): e is AgentMcpHTTPError =>
  e instanceof AgentMcpHTTPError && e.code === 'cave_auth_required';

Try / catch

try { return await agentMcpRequest(path, opts); } catch (e) {
  if (isAuthError(e)) { console.error('Run `caveman login` or set CAVE_TOKEN.'); process.exit(1); }
  throw e;
}

Prevention

When it happens

Trigger: Any CLI/agent command that reaches the MCP HTTP layer while `cfg.token` is empty: fresh install, CI container without login, expired/removed credentials, or CAVE_TOKEN unset in the environment.

Common situations: Running in a headless CI job where interactive `caveman login` is impossible, switching machines and forgetting to log in, or a config reset that wiped the stored token.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/f6909eabce4b15fc. Report an issue: GitHub.

Appendix: source

Thrown at packages/cli/src/index.ts:18372

    this.name = "AgentMcpHTTPError";
    this.code = code;
    this.status = status;
  }
}

function agentMcpTimeoutMS(): number {
  const raw = process.env.CAVE_AGENT_TOOL_TIMEOUT_MS ?? "30000";
  const value = Number(raw);
  return Number.isSafeInteger(value) && value >= 100 && value <= 120_000 ? value : 30_000;
}

async function agentMcpRequest(
  path: string,
  options: { method?: "GET" | "POST"; body?: JSONObject } = {},
): Promise<JSONValue> {
  const cfg = await config();
  if (!cfg.token) {
    throw new AgentMcpHTTPError(
      "Not logged in. Run `caveman login` or set CAVE_TOKEN for headless use.",
      "cave_auth_required",
      401,
    );
  }
  let response: Response;
  try {
    const request: RequestInit = {
      method: options.method ?? "GET",
      signal: AbortSignal.timeout(agentMcpTimeoutMS()),
      headers: {
        authorization: `Bearer ${cfg.token}`,
        ...(options.method === "POST"
          ? { "content-type": "application/json", "x-cave-csrf": "cli" }
          : {}),
      },
    };
    if (options.method === "POST") request.body = JSON.stringify(options.body ?? {});

View on GitHub (pinned to 3ee70a1026)