abhigyanpatwari/GitNexus · error · BackendError

server

server

Error message

No response body

What it means

BackendError (code 'server') thrown by parseNdjsonGraphResponse() when response.body is null/undefined on a graph stream request. The NDJSON streaming parser needs a readable body to parse node/relationship records line-by-line; an absent body means the server sent a response with no stream (malformed server behavior or a proxy stripping the body). Status is taken from response.status.

Source

Thrown at gitnexus-web/src/services/backend-client.ts:757

  }

  const combined = new Uint8Array(downloaded);
  let offset = 0;
  for (const chunk of chunks) {
    combined.set(chunk, offset);
    offset += chunk.length;
  }
  return JSON.parse(new TextDecoder().decode(combined));
};

const parseNdjsonGraphResponse = async (
  response: Response,
  onProgress?: (downloaded: number, total: number | null) => void,
  maxNodes?: number,
  maxEdges?: number,
): Promise<{ nodes: GraphNode[]; relationships: GraphRelationship[] }> => {
  if (!response.body) {
    throw new BackendError('No response body', response.status, 'server');
  }

  const contentLength = response.headers.get('Content-Length');
  const total = contentLength ? parseInt(contentLength, 10) : null;
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  const nodes: GraphNode[] = [];
  const relationships: GraphRelationship[] = [];
  let buffer = '';
  let downloaded = 0;

  // Streaming circuit breaker (#2178): enforce the size limits mid-download as a
  // backstop when pre-fetch stats were missing. Same `> threshold` comparison as
  // decideSkipGraph. Throwing immediately after the offending push means a later
  // error record in the same chunk is never reached — the breaker wins.
  const overLimit = (): boolean =>
    (typeof maxNodes === 'number' && nodes.length > maxNodes) ||
    (typeof maxEdges === 'number' && relationships.length > maxEdges);

View on GitHub (pinned to d540b00184)

Solutions

  1. Check the backend version — the streaming graph endpoint must be implemented and enabled
  2. Inspect the response headers (Content-Type should be application/x-ndjson) and status in DevTools
  3. If behind a proxy, disable response buffering for the /api/graph streaming route (e.g. proxy_buffering off in nginx)
  4. Ensure no other code path consumed response.body before parseNdjsonGraphResponse runs

Example fix

// before — caller assumes the stream is always present
const resp = await fetchGraph(repo);
const { nodes, relationships } = await parseNdjsonGraphResponse(resp); // throws

// after — guard against an absent body
if (!resp.body) throw new Error('Backend returned no graph stream — check backend version/proxy');
const { nodes, relationships } = await parseNdjsonGraphResponse(resp);
Defensive patterns

Strategy: validation

Validate before calling

// Check response.body and Content-Type before handing to the NDJSON parser
if (!response.body) {
  throw new Error('Backend returned no graph stream — check backend version / proxy buffering');
}
const ct = response.headers.get('Content-Type') ?? '';
if (!ct.includes('ndjson') && !ct.includes('json')) {
  throw new Error(`Unexpected graph Content-Type: ${ct}`);
}

Type guard

import { BackendError } from './services/backend-client.js';
function isNoBodyError(e: unknown): e is BackendError {
  return e instanceof BackendError && e.code === 'server' && /No response body/.test(e.message);
}

Try / catch

try {
  return await parseNdjsonGraphResponse(response);
} catch (e) {
  if (e instanceof BackendError && e.code === 'server' && /No response body/.test(e.message)) {
    // backend or proxy stripped the stream — fall back to a non-streaming endpoint or chat-only
    enterChatOnlyMode();
    return { nodes: [], relationships: [] };
  }
  throw e;
}

Prevention

When it happens

Trigger: A graph fetch (e.g. fetchGraph) returns a Response whose .body is null. This can happen when the server returns a response with Content-Length but no body, when an intermediary proxy strips the streaming body, or when the response was already consumed/locked by another reader.

Common situations: A misconfigured reverse proxy (nginx/cloudflare) buffering or dropping the streaming response body; the backend sent a non-streaming response for a streaming endpoint; the response body was already read by error-handling code before reaching the parser; a server bug returning an empty body for a graph request.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/14bb57b8f779384b. Report an issue: GitHub.