Start with the thing that is easy to forget while looking at a red row: a failed deployment has not broken your site.
What is left is a diagnosis: work out which kind of failure this is, then either fix something or press one button.
The two kinds of failure
Every failure Leed records falls into one of two groups, and the difference decides everything you do next.
Content and template errors come from your own material — a page, a Handlebars template, a data file. They will fail identically every time, so Leed does not offer a retry for them: re-running the same commit would just reproduce the same error. You can tell one without reading the message at all, because where the Retry button would be there is gray text reading Content/template error — fix in content (hover it and the tooltip says Fix the content or template, then re-publish.).
Everything else — an infrastructure hiccup, a build that ran out of time, an upload that did not complete — is outside your control and is offered as retryable.
Leed decides which is which by looking at the front of the stored error message: anything the site build itself threw is tagged, and everything untagged is treated as retryable. That is a good heuristic rather than a proof. Read it as Leed offers Retry when the failure looks like something a re-run can fix, and if a retry fails a second time in exactly the same way, treat it as a content problem regardless of what the button offered.
flowchart TD
A{"Is the error tagged as a site-build error?"} -->|Yes| B["Fix the page or template<br/>and publish again"]
A -->|No| C{"Is this the newest row<br/>for this site?"}
C -->|Yes| D["Press Retry"]
C -->|No| E["Publish again —<br/>Retry only runs the newest row"]
Reading the error
Expand the failed row. The drawer leads with a red Error block holding what the build reported.
The first thing to look at is how the message starts, because the prefix names the phase that failed and answers the retry question on its own:
| Starts with | Phase | Retryable | What to do |
|---|---|---|---|
[site-build] | Your content or templates failed to build | No | Read the message, fix what it names, publish again |
[version-upload] | The finished site could not be uploaded | Yes | Retry |
[upload] | The build produced no site to upload | Yes | Retry |
| (no prefix) | Infrastructure, a timeout, or an internal step | Yes | Retry |
A [site-build] message is the useful one, because it is the build’s own words about your material and it usually names a file or a page:
[site-build] Error in ./src/_layouts/blog.hbs
Missing helper: "featureImage"
at Template.render (src/_layouts/blog.hbs:41:8)What you are reading is an extract, not the whole build log. Where the build tooling summarizes a failing sub-process it keeps the marked error lines and the indented lines beneath them, up to about two thousand characters, and drops the progress output around them. That is deliberate — the useful part of a failed upload is buried under a long list of successfully uploaded files — but it does mean you are seeing the part that looked like the failure rather than every line the build printed.
Fixing a content or template error
The loop is short:
- Read the message for the file or page it names.
- Fix it — in the page editor if it names a page, in your templates if it names a
.hbsfile. - Publish again.
Publishing again is the fix. There is nothing to retry, because a retry would rebuild the same commit — the one without your correction in it. Build errors you can reproduce on your own machine are much faster to work through than ones you diagnose one deployment at a time; building the site locally turns a two-minute round trip into a few seconds.
Using Retry
Retry sits at the right-hand end of the collapsed row, in amber, and only ever on the newest failed row for that site.
Pressing it re-runs the same commit as a brand-new deployment. It creates no new commit, changes nothing about your content and touches no setting. A Retry started toast confirms it, and a new row appears at the top of the column carrying the same blue reason badges as the row it came from — with your name on it, because you started this one.
The four rules that hide the button
Retry only renders when all four of these are true:
- The row is the newest one for its site.
- Its status is failed.
- The failure is classified as retryable — not a
[site-build]error. - You hold the
deployment:publishprivilege.
If a request gets past the interface anyway, the server applies the same rules and answers with its own message:
| Status | Message | Why |
|---|---|---|
| 404 | Deployment not found | The id does not exist |
| 403 | Cross-company retry requires admin | The deployment belongs to another workspace |
| 400 | Only failed deployments can be retried | The row is not in the failed state |
| 400 | This build failed due to a content/template error and must be fixed in the content | The error is tagged [site-build] |
| 400 | Only the most recent deployment for a branch can be retried | Something has already been published since |
That last one comes up more often than the others, and it is not a restriction so much as a redirect: if you have published again since this row failed, retrying it would rebuild a commit that has already been superseded. Retry the newest row instead, or simply publish again.
The failures you can actually hit
The full catalog of failure modes
| What happened | What you see | Recovery |
|---|---|---|
| The build ran past its time limit | A failed row with no error message | Retry |
| Cloudflare’s build failed or was canceled | A failed or canceled row | Retry, unless the message is tagged [site-build] |
| Your content or a template did not build | A failed row, [site-build] in the error block, no Retry button | Fix the content or template, publish again |
| The site uploaded but Leed was never told | A failed row, no error message, after a long wait | Retry — the next build supersedes the orphaned upload |
| The commit was rewritten while the build was starting | Nothing. Leed detects it and builds the branch head instead | No action; this heals itself |
| A retry was attempted on a row that is no longer the newest | Only the most recent deployment for a branch can be retried | Retry the newest row, or publish again |
One of those deserves calling out, because it is the single case where “failed” does not mean “nothing happened”. If your site uploads successfully but the message telling Leed so never arrives, the version really was uploaded — it just never got activated, and the deployment is marked failed when the wait times out. The visible effect is still the same as any other failure: the old version keeps serving, and nothing on your site changed. Retrying produces a fresh build that does report back.
Failures during a preview build block promotion
This is the connection people miss. A red row in the Preview site column is the usual reason Push preview live refuses to do anything: promotion is blocked outright while the preview site’s latest deployment is in an error state, and the card says so in a red alert rather than a muted hint.
The fix is always on the preview side. Clear the preview failure — retry it if it is retryable, fix the content if it is not — and the button comes back on its own. Every reason promotion is disabled lists the other five.
If the failure came from your own leed site push, the CLI printed its own diagnosis before Leed ever saw the build — CLI troubleshooting and exit codes covers what it says and what each code means, and what a push actually triggers covers the handoff between the two.
When it is not your problem
A small class of failure happens before your site is ever rendered. The clearest signal is a build that stops almost immediately with a message about required environment variables not being set. That is a provisioning problem inside Leed’s own build configuration for your workspace — there is no content you can change to fix it, and retrying will fail the same way.
Contact Leed support with the deployment’s commit and the message from the error block. That pair is enough to identify the build on our side.
Finding and expanding the row in the first place is covered in reading a deployment row, and the wider list of messages you might be quoting lives in common error messages.