decolua/9router · error

[antigravity] ${error.message}

Error message

[antigravity] ${error.message}

What it means

The antigravity MITM handler intercepts requests, remaps the model, forwards the body to the local router's /v1/chat/completions, and pipes the SSE response back. Any failure in that pipeline (body parse, model mapping, router fetch, SSE piping) is logged as '[antigravity] <message>'; for stream requests it emits an SSE error chunk so the SDK does not hang, otherwise a JSON error response.

Source

Thrown at src/mitm/handlers/antigravity.js:20

const { IS_DEV } = require("../config");
const { fetchRouter, pipeSSE } = require("./base");

/**
 * Intercept Antigravity request — forward Gemini body as-is to /v1/chat/completions.
 * Router auto-detects format via body.userAgent==="antigravity" + body.request.contents,
 * runs antigravity→openai→provider→openai→antigravity translators internally.
 */
async function intercept(req, res, bodyBuffer, mappedModel) {
  const dumper = IS_DEV ? createResponseDumper(req, "intercept-antigravity") : null;
  const isStream = req.url.includes(":streamGenerateContent");
  try {
    const body = JSON.parse(bodyBuffer.toString());
    if (body.model) body.model = mappedModel;

    const routerRes = await fetchRouter(body, "/v1/chat/completions", req.headers);
    await pipeSSE(routerRes, res, dumper);
  } catch (error) {
    err(`[antigravity] ${error.message}`);
    if (dumper) { dumper.writeChunk(`\n[ERROR] ${error.message}\n`); dumper.end(); }
    // For stream endpoint, send SSE error chunk so SDK doesn't hang waiting
    if (isStream) {
      if (!res.headersSent) res.writeHead(200, { "Content-Type": "text/event-stream" });
      res.end(`data: ${JSON.stringify({ error: { message: error.message } })}\r\n\r\n`);
    } else {
      if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
      res.end(JSON.stringify({ error: { message: error.message, type: "mitm_error" } }));
    }
  }
}

module.exports = { intercept };

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Verify the 9Router gateway is running on the port the MITM proxy forwards to (default 20128).
  2. Check the error message in the dump file / logs — JSON parse errors mean the tool sent a non-JSON body; router errors mean check the router's own logs.
  3. Confirm the requested model has a mapping in the model-map config for antigravity.
  4. Retry the request; transient SSE disconnects are surfaced here but are often upstream-side.

Example fix

// before: router not running
fetch http://127.0.0.1:20128/v1/chat/completions -> ECONNREFUSED
// after: start the gateway first
PORT=20128 npm run start  # then retry the tool request
Defensive patterns

Strategy: try-catch

Validate before calling

// before routing, verify the gateway is up
const health = await fetch('http://127.0.0.1:20128/dashboard').then(r => r.ok).catch(() => false);
if (!health) throw new Error('Router gateway not running on :20128');
JSON.parse(bodyBuffer.toString()); // fail fast on malformed body

Try / catch

try {
  const routerRes = await fetchRouter(body, '/v1/chat/completions', req.headers);
  await pipeSSE(routerRes, res, dumper);
} catch (error) {
  err(`[antigravity] ${error.message}`);
  if (isStream && !res.headersSent) {
    res.writeHead(200, { 'Content-Type': 'text/event-stream' });
    res.end(`data: ${JSON.stringify({ error: { message: error.message } })}\r\n\r\n`);
  }
}

Prevention

When it happens

Trigger: intercept() called with malformed JSON body (JSON.parse throws), router not running on the local port (fetchRouter fails), model name with no mapping, or the SSE stream from the router aborts mid-pipe.

Common situations: Tool configured to point at the MITM proxy before `9router` server is started; antigravity CLI updated to a model id the mapper doesn't know; request body format changed upstream.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/8775c0854e2d0458. Report an issue: GitHub.