Summary
The Kilo documentation deployment can intermittently fail during the Vercel onBuildComplete hook with a missing docs/404.html. The application compilation and static page generation finish successfully; the failure occurs while the Vercel adapter materializes static outputs.
This issue tracks upgrading the docs site to the first stable Next.js release containing vercel/next.js#95681. That upstream change fixes the actual duplicate-output bug. Until then, a cache-free redeployment is an operational recovery only and does not eliminate the race.
Related Kilo PR where the failure was observed: Kilo-Org/kilocode#12197.
Sanitized failure signature
Running onBuildComplete from Vercel
Failed to run onBuildComplete from Vercel
Error: ENOENT: no such file or directory, chmod
<checkout>/packages/kilo-docs/.next/output/static/docs/404.html
No application compilation error precedes this. Next.js reports that all static pages were generated before the hook fails.
Root cause
The affected build uses Next.js 16.2.9, a Pages Router custom 404 page, and basePath: "/docs":
Next.js 16.2.9 adds the same auto-static 404 output twice:
- The normal auto-static page path adds
/404 to outputs.staticFiles: build-complete.ts lines 904-912.
- The later error-page fallback path adds
/404 again without checking whether that pathname was already emitted: build-complete.ts lines 1890-1920.
Both entries have the same pathname and source file:
/docs/404 -> <checkout>/packages/kilo-docs/.next/server/pages/404.html
/docs/404 -> <checkout>/packages/kilo-docs/.next/server/pages/404.html
The Vercel adapter handles static outputs concurrently and maps both entries to the same destination. Its copy helper removes the destination before copying:
A possible interleaving is:
copy A writes docs/404.html
copy B removes docs/404.html
copy A attempts chmod on docs/404.html
copy A receives ENOENT
This is timing-dependent. Restored build cache state changes filesystem timing, which explains why one cached deployment failed while a subsequent cache-free deployment of the same commit succeeded. Clearing the cache does not fix the duplicate outputs.
The diagnosis matches the upstream report exactly. The upstream PR states that duplicate static entries cause concurrent file-operation races in the Vercel adapter:
Deterministic reproduction
The Vercel ENOENT itself is timing-dependent, but the invalid duplicate adapter output is deterministic.
- Check out Kilo commit
0f7c46c15bcff2fde243f7af9db2ec301070ef98 or another commit using Next.js 16.2.9 with the same docs 404 page.
- Install dependencies from the lockfile.
- Create
packages/kilo-docs/adapter-debug.cjs:
module.exports = {
name: "diagnostic",
onBuildComplete({ outputs }) {
console.log(
outputs.staticFiles.filter(
(output) => output.pathname === "/docs/404",
),
)
},
}
- Run the docs build with the diagnostic adapter:
NEXT_ADAPTER_PATH="$PWD/packages/kilo-docs/adapter-debug.cjs" \
bun run --cwd packages/kilo-docs build
- Observe two identical
/docs/404 entries in outputs.staticFiles.
- Delete the diagnostic adapter after reproduction.
Release status at time of filing
- Project lockfile resolves Next.js
16.2.9.
- Stable Next.js
16.2.10 was published before the upstream fix merged and still contains the duplicate-output logic.
16.3.0-canary.85 contains the fix, but moving the docs site to a broad canary is not justified for this intermittent deployment issue.
- The upstream fix merged on July 13, 2026. Wait for a stable release that contains commit
db1f3a64daf26f8c3866cc7d6e96b6c3f70d5b6b.
Implementation once released
- Identify the first stable Next.js version containing the upstream fix commit.
- Upgrade
next in packages/kilo-docs/package.json and regenerate bun.lock.
- Repeat the diagnostic adapter reproduction and confirm exactly one
/docs/404 static output.
- Run the docs build, typecheck, tests, and lint.
- Verify a Vercel preview deployment that restores its normal build cache completes
onBuildComplete successfully.
- Remove any temporary workaround if one was introduced before the stable upgrade.
Acceptance criteria
- The docs package uses a stable Next.js release containing #95681.
outputs.staticFiles contains only one /docs/404 entry.
- Cached and cache-free Vercel preview builds complete successfully.
- The custom static 404 page still renders with an HTTP 404 response.
Workarounds to avoid unless deployment becomes repeatedly blocked
- Do not remove the custom 404 page.
- Do not add
getStaticProps solely to change the page from a static-file output to a prerender output; that avoids the race but changes deployment behavior.
- Do not carry a local patch of compiled Next.js output if waiting for the stable release remains operationally acceptable.
- Do not pin the docs site to a broad Next.js canary solely for this fix.
Summary
The Kilo documentation deployment can intermittently fail during the Vercel
onBuildCompletehook with a missingdocs/404.html. The application compilation and static page generation finish successfully; the failure occurs while the Vercel adapter materializes static outputs.This issue tracks upgrading the docs site to the first stable Next.js release containing vercel/next.js#95681. That upstream change fixes the actual duplicate-output bug. Until then, a cache-free redeployment is an operational recovery only and does not eliminate the race.
Related Kilo PR where the failure was observed: Kilo-Org/kilocode#12197.
Sanitized failure signature
No application compilation error precedes this. Next.js reports that all static pages were generated before the hook fails.
Root cause
The affected build uses Next.js
16.2.9, a Pages Router custom 404 page, andbasePath: "/docs":Next.js
16.2.9adds the same auto-static 404 output twice:/404tooutputs.staticFiles: build-complete.ts lines 904-912./404again without checking whether that pathname was already emitted: build-complete.ts lines 1890-1920.Both entries have the same pathname and source file:
The Vercel adapter handles static outputs concurrently and maps both entries to the same destination. Its copy helper removes the destination before copying:
copyremoves and then copies the destinationhandleStaticOutputsruns concurrent copies to the derived pathnameA possible interleaving is:
This is timing-dependent. Restored build cache state changes filesystem timing, which explains why one cached deployment failed while a subsequent cache-free deployment of the same commit succeeded. Clearing the cache does not fix the duplicate outputs.
The diagnosis matches the upstream report exactly. The upstream PR states that duplicate static entries cause concurrent file-operation races in the Vercel adapter:
db1f3a64daDeterministic reproduction
The Vercel ENOENT itself is timing-dependent, but the invalid duplicate adapter output is deterministic.
0f7c46c15bcff2fde243f7af9db2ec301070ef98or another commit using Next.js16.2.9with the same docs 404 page.packages/kilo-docs/adapter-debug.cjs:NEXT_ADAPTER_PATH="$PWD/packages/kilo-docs/adapter-debug.cjs" \ bun run --cwd packages/kilo-docs build/docs/404entries inoutputs.staticFiles.Release status at time of filing
16.2.9.16.2.10was published before the upstream fix merged and still contains the duplicate-output logic.16.3.0-canary.85contains the fix, but moving the docs site to a broad canary is not justified for this intermittent deployment issue.db1f3a64daf26f8c3866cc7d6e96b6c3f70d5b6b.Implementation once released
nextinpackages/kilo-docs/package.jsonand regeneratebun.lock./docs/404static output.onBuildCompletesuccessfully.Acceptance criteria
outputs.staticFilescontains only one/docs/404entry.Workarounds to avoid unless deployment becomes repeatedly blocked
getStaticPropssolely to change the page from a static-file output to a prerender output; that avoids the race but changes deployment behavior.