Troubleshooting

Grouped by what you see, with the exact text the relay returns.

I sent a request and nothing appeared in the log

Three causes, in order of likelihood:

  1. The endpoint runs in Tunneling with save off. Tunneling forwards without recording unless Save full request & response is on (it is on by default). Stop the endpoint and start it again with that checkbox enabled if you want both.
  2. The list has not caught up yet. It polls every few seconds; Refresh above the list fetches immediately.
  3. The request never arrived. Run the request with curl -i and read the status. A recorded request always returns something from the relay, so a connection error means it did not reach us at all.

I get 204 No Content and my local service sees nothing

That is Logging working as designed: the relay records the request and answers 204 without forwarding. Restart the endpoint in Tunneling to reach your machine.

I get 503 No agent for client

The relay has no live HTTP agent for that host. Any of these produce it:

  • the desktop app or the npm CLI is not running, or is signed out / unauthenticated
  • the app lost its network, and the claim lapsed after 15 seconds without a heartbeat
  • the endpoint was started but the agent has not registered yet — wait a moment and retry
  • the hostname does not match an endpoint, usually a typo in the subdomain
  • the endpoint speaks a different protocol than the request, for example plain HTTP or Socket.IO polling sent to a WebSocket endpoint

The body is text/plain with no Access-Control-Allow-Origin. A browser XHR from another origin reports this as CORS. Confirm with curl:

Run
curl -i https://your-endpoint.mercur.sh/socket.io/?EIO=4&transport=polling

The browser reports CORS, curl shows 503

Cross-origin XMLHttpRequest (including Socket.IO transport=polling) requires Access-Control-Allow-Origin on the response. Mercur 503, 502, 403, and 429 replies do not include CORS headers, so Chrome reports a CORS failure even when the relay answered with a clear error body.

Default Socket.IO starts with HTTP polling to /socket.io/, then tries WebSocket upgrade. Mercur HTTP endpoints forward GET/POST and do not proxy upgrade. Mercur WebSocket endpoints accept upgrade and do not serve polling. Polling a WebSocket endpoint is HTTP on a WS host, which is the wrong-protocol case of 503 No agent for client above.

If curl returns Engine.IO JSON and the browser still fails CORS, the page origin (for example http://localhost:63342) is not in the local Socket.IO cors.origin list. Allow that origin, or serve the HTML through the same tunnel so the request is same-origin. transports: ["websocket"] only helps on a WebSocket endpoint.

The HTTP agent buffers the full upstream body. Socket.IO long-poll through an HTTP tunnel stays a poor fit even after CORS is correct.

Walkthrough: Inspect a WebSocket session. Release notes: Inspect WebSocket traffic on a localhost tunnel.

I get 503 Server is not running

The endpoint exists but is stopped, starting, or failed. Open it in the console and press Enable. Seeing this immediately after enabling is normal for a moment, while the agent registers.

I get 403 Forbidden

The endpoint is not public and your address is not on its list. Add the caller's address to the IP whitelist, or set Public access to true. Remember that the caller is often not you — a webhook provider calls from its own ranges.

I get 429

You reached the monthly request quota for your plan and the body says Monthly HTTP request quota exceeded. Quotas reset monthly; see limits.

I get 503 Too many concurrent sessions

More connections were open at once than your plan allows. In-flight requests finish and free the slots. Long-lived requests hold a slot for their whole duration, so a slow endpoint reaches this sooner.

I get 502 with connect ECONNREFUSED 127.0.0.1:3000

The relay reached your machine and your machine refused the connection. Your local process is not listening, or is listening on a different port than the one you entered when you started Tunneling. Check with curl -i localhost:3000 first — if that fails, the problem is entirely local. Longer walkthrough: Webhook 502 localhost. Port conventions for Next.js (3000) vs Uvicorn/Django (8000): framework webhook localhost.

I get 502 Bad Gateway with no detail

The connection between the relay and your agent failed mid-request. Stop and start the endpoint, then retry.

Connections tab is empty

The Connections tab exists only on WebSocket endpoints. An HTTP endpoint shows request history instead. If the endpoint is WebSocket and the list stays empty:

  • the agent is not claimed (same causes as 503 No agent for client)
  • no public client completed Upgrade
  • you are looking at a share link that expired

Failed handshakes can still appear as state: error. How-to: Inspect a WebSocket session.

My WebSocket or TCP connection is dropped without an error

Rejections before a WebSocket handshake completes close the socket without an HTTP response, so a client only reports a reset connection. The causes are the same as the HTTP list above: unknown host, stopped endpoint, address not allowed, no agent, quota, or session limit. Check the endpoint in the console. On a WebSocket endpoint, an error row on the Connections tab is the inspectable form of that failure.

WebSocket and TCP also require a plan that includes them. Solo and Team include both; Guest and Free stay HTTP-only. See limits.

The console will not let me run the endpoint

  • Endpoint is in use by <hostname> — another machine holds this endpoint. Stop it there first.
  • Running this mode requires the Electron app with a connected device agent — forwarding from the browser is refused; use the desktop app or the npm CLI. The browser can run Logging only.
  • Endpoint must be stopped before changing its run mode — stop it, then start it in the mode you want.
  • Device agent credential is invalid — sign in again in the desktop app, or run mercur auth again with a valid CLI token, so the machine registers anew.

The CLI will not start a tunnel

  • No CLI token found — HTTP still works without an account: npx @mercur_dev/cli http 3000. For a workspace, create a token under Settings → CLI tokens (pick a workspace) and run mercur auth, or set MERCUR_TOKEN in CI. Tokens start with mcrcli_. Customer-scoped tokens minted before this change no longer work.
  • Occupied endpoint — the desktop app or another CLI already holds it. Stop it there, or wait for a crashed holder's heartbeat to expire.
  • Wrong console — a token created on a local console will not work against production. Set MERCUR_API_URL if you are not using https://console.mercur.sh.

Walkthrough: CLI agent.

A response body is missing from a recorded request

Response recording is a separate setting from request recording, and it only applies in Tunneling. Enable Save full request & response when starting the endpoint. Logging never has a response to store, because nothing is forwarded.

Old requests disappeared

Each plan caps how many requests an endpoint keeps, and the oldest are dropped past the cap. Everything is deleted 30 days after arrival regardless. See limits.