Skip to content

fix(wanderweird): keep the gateway up when an upstream is not JSON - #488

Draft
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-1c0d
Draft

cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-1c0d

Conversation

@cursor

@cursor cursor Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Problem

The gateway change that answers 502 when an upstream is down still crashes the process.

Express 4 does not catch a rejected async handler. proxyJson only caught fetch throwing (ECONNREFUSED). The body was then read with response.json().catch(() => response.text()). After a failed JSON parse the body is already consumed, so text() throws Body is unusable. That rejection is outside the try/catch, so Node exits and every other gateway route dies with it.

/graphql never used proxyJson. A down GraphQL upstream (ECONNREFUSED on port 4206) rejects the handler the same way.

Trigger: start the gateway, leave GraphQL down, and POST /graphql. Or call any proxied route whose upstream returns HTML or plain text (a 502 error page).

Solution

Read the upstream body once as text, then JSON.parse. Connection failures and unreadable bodies return 502 JSON. /graphql uses that helper.

Changes

  • Add proxyJson / readUpstreamBody and route GraphQL through them.
  • Lock the behavior in with unit tests.

How it works

Non-JSON and unreachable upstreams resolve instead of rejecting:

export async function readUpstreamBody(response: Response): Promise<unknown> {
  const text = await response.text();
  if (!text) return null;
  try {
    return JSON.parse(text) as unknown;
  } catch {
    return text;
  }
}

GraphQL uses the same helper as the REST routes:

const result = await proxyJson(target, init);
res.status(result.status).json(result.body);

A down GraphQL service now answers 502 JSON:

curl -s -X POST http://127.0.0.1:4200/graphql \
  -H 'content-type: application/json' \
  -d '{"query":"{ __typename }"}'

Testing

  • npx jest tests/gateway-proxy-json.test.ts — 5 passed (JSON body, HTML body, empty body, ECONNREFUSED → 502, non-JSON status preserved).
  • npm test — 138 suites passed, 1 skipped; 1196 passed, 7 skipped.
Open in Web View Automation 

Express 4 does not catch rejected async handlers. Reading the body with
json().catch(text()) throws after a failed parse, and /graphql never used
the 502 helper. Read the body once and send GraphQL through the same path.

Co-authored-by: Sebastian Gedda <sebastian.gedda@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant