fix(deps): revert next to 16.2.12, its 16.3.0 optimizer deletes live code - #6242
Conversation
…code Next 16.3.0's Turbopack optimizer models a bare `return <asyncCall>()` tail call inside an async function as returning the promise object, then propagates that always-truthy fact through the caller's `await`. Where the result feeds an `if (x)` whose every branch returns, it concludes the branch is always taken and deletes everything after it from the emitted bundle. Two sites shipped to production that way: - `POST /api/credentials` lost its entire create path — the transaction, the org locks, the insert, the audit, the 201. A first-time create fell into the existing-credential branch and threw on `existingCredential.id`, so every new credential 500'd. - `upsertAsyncToolCall` collapsed to `async () => await getAsyncToolCall(id)`. The insert is simply gone; it returns null for every new async copilot tool call. Silent — no error, no failed request. A differential scan of 71,266 source string literals across `.next/server` and `.next/static`, comparing images built from the same commit on 16.2.12 and 16.3.0, found exactly these two and nothing else. That scan cannot see dropped branches with no distinctive string literal, which is why the version goes back rather than the two sites being patched alone. Both are also hardened with `return await`, verified to defeat the miscompile in a minimal reproduction. The TypeScript toolchain cleanup from the original bump (dropping @typescript/native-preview, `useTypeScriptCli`) is kept.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryHigh Risk Overview Hardening:
Reviewed by Cursor Bugbot for commit 6de3c44. Configure here. |
Greptile SummaryThis PR consistently reverts Next.js and its associated environment and compiler packages from 16.3.0 to 16.2.12 to avoid a confirmed Turbopack optimizer regression, while retaining explicit compiler workarounds.
Confidence Score: 5/5The PR appears safe to merge; the downgrade is consistent across manifests and the lockfile, and the async hardening preserves existing runtime behavior. The changed dependency graph resolves coherently to Next 16.2.12 across supported build targets, while the explicit awaits preserve transaction, tracing, error, and promise semantics and prevent the reported optimizer failure.
|
| Filename | Overview |
|---|---|
| package.json | Aligns root Next, @next/env, and explicitly installed SWC packages on 16.2.12. |
| bun.lock | Resolves a coherent Next 16.2.12 graph, including matching environment, SWC, PostCSS, and Sharp packages. |
| apps/sim/app/api/credentials/route.ts | Adds explicit awaits to prevent the documented optimizer from deleting the credential creation path. |
| apps/sim/lib/copilot/async-runs/repository.ts | Hardens traced async database wrappers against the same optimizer misclassification without changing runtime contracts. |
| apps/sim/next.config.ts | Retains configuration compatible with 16.2.12 and clarifies why explicit cache and TypeScript CLI settings remain necessary. |
Reviews (1): Last reviewed commit: "fix(deps): revert next to 16.2.12, its 1..." | Re-trigger Greptile
Picks up the Next 16.2.12 revert (#6242). The earlier merge had taken staging's 16.3.0; this takes the revert in apps/docs, apps/sim and packages/emcn and regenerates the lockfile. lucide-react stays removed.
Summary
next16.3.0 -> 16.2.12 across the root overrides,@next/swc-*optional deps,apps/sim,apps/docs, andpackages/emcn. Keeps the TypeScript toolchain cleanup from the original bump (@typescript/native-previewdropped,useTypeScriptClipinned).return <asyncCall>()tail call inside anasyncfunction as returning the promise object, then carries that always-truthy fact through the caller'sawait. Where the result feeds anif (x)whose every branch returns, it decides the branch is always taken and deletes everything after it from the emitted bundle.POST /api/credentialslost the whole create path (transaction, org locks, insert, audit, 201). New credentials 500'd withTypeError: null is not an object (evaluating 'K.id')— this is the prod canary failure.upsertAsyncToolCallcollapsed toasync () => await getAsyncToolCall(id). The insert is gone; it returnsnullfor every new async copilot tool call. Silent — no error, no failed request, no canary.return await, which defeats the miscompile in a minimal reproduction.Scope
Built the same commit on 16.2.12 and 16.3.0 and diffed 71,266 distinctive source string literals across
.next/serverand.next/static. Exactly two literals disappeared — the two above; the client bundle lost none. That scan cannot see dropped branches containing no distinctive string, which is why the version goes back rather than patching the two sites and calling it done.Type of Change
Testing
return await, dropping the wrapper,!== null, and hoisting to a nullableleteach fix it.apps/sim/app/api/credentials/route.test.tspasses (6/6).Checklist