Reading a deploy's timeline
Find the deploy that failed, see which phase it died in, read what your own commands printed, and retry it.
Every deploy records what it did, phase by phase, with how long each phase took and what the failure was. This page shows you how to read that record and get from "the instance won't open" to "the install command is broken" in about thirty seconds.
Finding a deploy
Open the project and choose Deploy health in the sidebar.
The top of the page answers "is this normal?" — the share of deploys that succeeded, how long an average deploy takes, and how many failed in the last thirty days, with a chart of deploys per day. Under that, Unhealthy scenes lists the scenes that have failed recently, so a scene that is broken for everyone stands out from a one-off blip.
Deploys below that is the full list: every deploy, newest first, grouped by day. Each row carries the scene name, the test file it runs, the error code if it failed, when it started, and how long it took. Filter to Failed, In flight, or Ready with the buttons above the list.
A deploy in flight updates on its own — leave the page open and watch it move.
The phase timeline
Open a deploy to see the phases it went through:
| Phase | What happens |
|---|---|
| Boot | The container your app runs in starts up and reports for duty. |
| Clone repo | We fetch your repository at the capture's commit. |
| Build plan | We read midstream.json and work out what to run. |
| Install | Your install command runs. |
| Install browser | We make sure the container has the Chromium build your Playwright version asks for. |
| Start app | Your start command runs, and we wait for the app to answer on its port. |
| Run test to scene | Your test runs and stops at the scene, and we capture the session there. |
Each phase shows one of these states:
- A duration — it finished, and that is how long it took.
- cached — it was skipped, because an earlier deploy of this instance already did the work. Resumed instances often skip the clone and the install, which is why a second open is so much faster than the first.
- not needed — only on the browser step, and only for a project with no Playwright of its own in the container. There was no browser to install.
- Spinning, with a running clock — it is happening now.
- failed after… — it died here. The error opens inline underneath.
- — — it never ran, because something before it failed.
The phases run in that order, and a deploy stops at the first one that fails, so the timeline reads as one story: everything above the failure worked, nothing below it was attempted.
The error
Under the phase that failed you get five things:
- The code, such as
SANDBOX_INSTALL_FAILED. Every code is listed in Why a deploy failed. - Whose side it is on — "project issue" or "midstream infra".
- Whether it is transient, meaning a retry has a real chance of working.
- The command it ran, verbatim from your
midstream.json. "The start step failed" tells you which phase;./scripts/start.shtells you which file to open. - The raw output from that command.
A deploy that ran out of time gets one more line: the budget it ran out of, and the one every project gets. "Failed after 3m 0s" is not much on its own — the point is that the 3m is ours, not your test's, and a project that legitimately needs longer can be given more. See Time limits.
Command output
Every phase that runs a command from your midstream.json keeps what that
command printed, under Command output on the phase itself. The phase that
failed opens by default; the others fold away.
Three things worth knowing about it:
- It arrives while the command is still running. A deploy you open mid-flight streams its output into the page. This is the point: a start command that hangs never finishes, so waiting for it to finish would show you nothing in exactly the case you most need to see.
- Successful phases keep their output too. The warning that explains a failure is often printed by the step before it.
- A very long log keeps its end, not its beginning. If a command prints more than we store, we drop from the front and say how much — the end is where the failure is.
Output is shown to workspace members only. Someone who opened an instance link sees a short message and nothing else — no commands, no output, no stack traces.
Reading it without the page
The same output is available over the API, so you can point an agent at a failing deploy instead of copying text out of a browser:
curl -H "Authorization: Bearer $MIDSTREAM_API_KEY" \
"https://midstream.studio/api/v1/instances/deploys/$DEPLOY_ID/logs"You get one entry per step, each with the step name, its output, and whether
the log was cut. Deploy ids come from
/api/v1/instances/deploys?workspaceSlug=…&projectSlug=…, which also carries
each deploy's error code and the command that failed. The error codes are
stable and enumerable — the catalog is
the full list — so an agent can branch on the code rather than parse a message.
Running the test locally
Each deploy also records exactly what it was trying to run: the test file, the chain of test titles within it, and the commit. Alongside them:
npx midstream your-scene-slugBe clear about what that does and does not do. It finds the test containing the
scene and runs it headed against an app you are already running, pausing at
the scene. It does not run your install or start command, and it does not
start from a cold container — so it is the right tool for a test that stops
short of the scene, and the wrong one for an install or start command that
fails. For those, the command output above is the reproduction.
Retrying
If the deploy failed, Retry provision at the top of the page starts a fresh one against the same capture. The failed deploy stays in the list — the history is the point, so "it failed twice and then worked" remains answerable.
You cannot retry a deploy that is still in flight or one that succeeded. Wait for it, or reset the instance from its toolbar.
Retrying requires workspace membership.