Webhook 502 localhost
What this symptom means
502 with a body like connect ECONNREFUSED 127.0.0.1:3000 means the Mercur agent was connected, the relay accepted the provider’s POST, and your machine refused the TCP connection to the Endpoint’s local port. The process is not listening, or it is listening on a different port than the Endpoint setting.
This is documented in troubleshooting. It is not “unknown host” (503 No agent for client), not an app-level 404/500, and not a provider timeout while your handler ran slowly.
Guest inspector never dials localhost, so it cannot return this 502. If you see 502 in a provider dashboard on a guest URL, that URL is not the inspector.
Common causes
- Local app not started, crashed, or still compiling
- Endpoint Local port is 3000, Next.js is on 3001 (or Vite 5173)
- App bound to IPv6
[::1]only while the agent dials127.0.0.1(or the reverse) - Port already taken, so your server exited; the Endpoint still points at the dead port
- Docker published another port than the one in Mercur
- You curled the Mercur URL after stopping
next devwithout stopping the Endpoint
Verify the incoming request
On the machine that runs the agent:
curl -i http://127.0.0.1:3000/Replace 3000 with the Endpoint’s local port. If that curl fails, Mercur will fail the same way. If localhost curl works but the public URL is 502, confirm the Endpoint port, then restart the agent.
Provider Recent Deliveries will show 502 and often the ECONNREFUSED text. Mercur console history (Log and Proxy) records the attempt; log-only mode would not dial localhost at all.
After 15 seconds without an agent heartbeat the failure becomes 503, not 502 — the claim lapsed. 502 is “agent up, port closed.”
Provider and framework notes
Stripe/GitHub/Telegram all surface the 502 as a failed delivery and may retry, which keeps hitting a closed port until you listen.
Next.js: next dev prints the port it bound. Match that number in the Endpoint. next start after a build uses 3000 by default unless -p is set. FastAPI/Uvicorn and Django runserver default to 8000 — FastAPI webhook localhost, Django webhook localhost.
Docker Compose ports: "3000:3000" still requires the process inside the container to listen; the agent on the host should target the published host port.
This page is Mercur-specific. Other tunnels use similar wording (connection refused); the relay’s exact body is connect ECONNREFUSED ….
Debugging checklist
curl -i localhost:<Local port>on the agent machine.- Align Endpoint local port with the process.
- Bind the app to
127.0.0.1(or match IPv6 if that is what you set). - Restart Log and Proxy after the app is actually listening.
- Recheck the public URL with curl; expect your app’s status, not 502.
Confirm with the webhook inspector
To see the payload without needing localhost up, use the inspector. Guest: 204, no agent, idle TTL 1 day, cap 256 KB. That confirms the provider. 502 only appears after you Connect and the port is wrong.
Inspect the request Connect localhost
Connect localhost
502 is the Connect path failing at the last hop. Install/start the macOS app or mercur start <endpointId>, set Local port, run the app, then Enable in Proxy or Log and Proxy.
Forwarding needs a connected agent — the macOS app or the npm package @mercur_dev/cli.
CLI details: CLI agent. App walkthrough: Expose a local service.
Replay the same event
Once localhost listens, Retry a stored 502 row to confirm the handler without another provider event. Needs the request still stored, proxy mode, agent connected, complete payload.
Retrying while the port is still closed produces another 502. Guest inspector has no Retry.