Vite Build Crashed After Emit? Check Fresh Output Before Failing the Build
On Windows, a Vite or Node.js build can sometimes crash after it has already emitted a valid dist/ directory.
That creates an awkward question: did the build fail, or did the tool crash during teardown after producing usable artifacts?
The wrong answer is to check only whether dist/ exists. A stale dist/ from a previous run can make a failed build look successful. The safer answer is to clean output first, run the build, then verify that the files were generated fresh in this run.
The failure pattern
The symptom often looks like this:
vite build
✓ built in 4.2s
process exited with code -1073741819
or a Windows access violation such as:
0xC0000005
The build log says files were built, but the process exits non-zero. If you are packaging a Tauri app or running CI, a strict non-zero exit code stops the release.
Sometimes that is correct. Sometimes the generated output is complete and fresh, and only the teardown path crashed.
Why dist exists is not enough
This check is unsafe:
vite build
test -f dist/index.html
If dist/index.html was created yesterday, the check still passes. You may ship stale files from a previous build.
A reliable check must prove:
dist/was cleaned before this runindex.htmlwas created during this run- referenced asset files exist
- required static assets, such as WASM files, are present and non-empty
PowerShell wrapper pattern
PowerShell works well as a parent process on Windows because a Node child crash does not usually kill the PowerShell wrapper.
$ErrorActionPreference = "Stop"
$Dist = Join-Path (Get-Location) "dist"
if (Test-Path $Dist) {
Remove-Item $Dist -Recurse -Force
}
npm run typecheck
npm run vite-build
$index = Join-Path $Dist "index.html"
if (-not (Test-Path $index)) {
throw "dist/index.html was not created"
}
$age = (Get-Date) - (Get-Item $index).LastWriteTime
if ($age.TotalSeconds -gt 10) {
throw "dist/index.html is stale"
}
For a production wrapper, capture the Vite exit code and then decide whether to accept a post-emit crash only if the freshness checks pass.
Retry only when the output is incomplete
If the process exits non-zero but output is fresh and complete, you may classify it as a post-emit crash. If output is missing or stale, retry.
exit 0 + fresh output -> success
exit non-zero + fresh output -> post-emit crash, optionally accept
exit non-zero + stale output -> real failed attempt, retry or fail
The important part is not to hide every non-zero exit code. TypeScript errors, missing imports, and incomplete assets should still fail the build.
When this applies
This pattern is useful when:
- the build log reports success but the process exits non-zero
- the crash is intermittent
- the crash appears on Windows during process cleanup
- packaging depends on generated frontend files
- you cannot trust a stale
dist/directory
It is especially useful in desktop app pipelines where a frontend build is followed by Tauri or another native packaging step.
Summary
Do not treat "dist exists" as proof of a successful Vite build.
Clean dist/, run the build, and verify fresh output. If the build crashes after emit, your wrapper can make a deliberate decision instead of confusing stale artifacts with success.