Skip to content

sandbox-cloudflare: exposePreview returns stale tunnels — no liveness check on the cached tunnel record #992

Description

@tombeckenham

Summary

The exposePreview tool in @tanstack/ai-sandbox-cloudflare (preview-tool) resolves the preview URL with a bare sandbox.tunnels.get(port). tunnels.get in @cloudflare/sandbox is idempotent per port: it returns the cached tunnel record from DO storage without verifying that the cloudflared process — or the server behind it — still exists. The record only clears on container restart.

Failure mode (observed on a live deploy)

  1. Agent starts a dev server on port N, calls exposePreview(N) → tunnel minted, URL works.
  2. The dev server (or cloudflared) dies later in the thread; the agent restarts the server.
  3. Agent calls exposePreview(N) again → tunnels.get returns the same dead URL from storage.
  4. User opens it → 502 at the trycloudflare edge (Unable to reach the origin service). From the agent's point of view the tool succeeded, so it confidently re-shares a dead link — there is no signal anywhere that anything is wrong.

This is deterministic: any container whose previewed process restarts while the container itself stays warm will reproduce it.

Suggested fix

Verify end to end before returning a URL, roughly:

  1. In-container probe — e.g. sandbox.exec("curl -s -o /dev/null -w '%{http_code}' --max-time 5 http://127.0.0.1:PORT/"). This also catches the wrong-port case where a dev server scan-forwards from its requested port.
  2. Edge probe — fetch the tunnel URL; any status < 500 means the origin answered, 502/530 is the stale signature.
  3. On staletunnels.destroy(port) then a fresh tunnels.get(port), with a short retry window for fresh-tunnel edge/DNS propagation, and a note in the tool result telling the agent the OLD url is dead so it re-shares the new one.
  4. On failure, return an actionable error ("nothing listening on port N inside the sandbox") instead of a URL that 502s.

We've been running exactly this shape as a drop-in replacement for the package tool and it closed the failure completely; happy to upstream it if you want a PR.

Environment

  • @cloudflare/sandbox 0.12.4 (SANDBOX_TRANSPORT: rpc), do-drives mode, quick tunnels (no PREVIEW_HOSTNAME)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions