When a Deployment Fails

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.).

A collapsed failed deployment row with the inline text Content/template error — fix in content in place of a Retry button

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 withPhaseRetryableWhat to do
[site-build]Your content or templates failed to buildNoRead the message, fix what it names, publish again
[version-upload]The finished site could not be uploadedYesRetry
[upload]The build produced no site to uploadYesRetry
(no prefix)Infrastructure, a timeout, or an internal stepYesRetry

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:

  1. Read the message for the file or page it names.
  2. Fix it — in the page editor if it names a page, in your templates if it names a .hbs file.
  3. 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.

A collapsed failed deployment row with a red Failed badge and an amber Retry button

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:

  1. The row is the newest one for its site.
  2. Its status is failed.
  3. The failure is classified as retryable — not a [site-build] error.
  4. You hold the deployment:publish privilege.

If a request gets past the interface anyway, the server applies the same rules and answers with its own message:

StatusMessageWhy
404Deployment not foundThe id does not exist
403Cross-company retry requires adminThe deployment belongs to another workspace
400Only failed deployments can be retriedThe row is not in the failed state
400This build failed due to a content/template error and must be fixed in the contentThe error is tagged [site-build]
400Only the most recent deployment for a branch can be retriedSomething 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 happenedWhat you seeRecovery
The build ran past its time limitA failed row with no error messageRetry
Cloudflare’s build failed or was canceledA failed or canceled rowRetry, unless the message is tagged [site-build]
Your content or a template did not buildA failed row, [site-build] in the error block, no Retry buttonFix the content or template, publish again
The site uploaded but Leed was never toldA failed row, no error message, after a long waitRetry — the next build supersedes the orphaned upload
The commit was rewritten while the build was startingNothing. Leed detects it and builds the branch head insteadNo action; this heals itself
A retry was attempted on a row that is no longer the newestOnly the most recent deployment for a branch can be retriedRetry 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.

ESC