vercel/next.js · error
gave up applying effects after {MAX_RETRIES} retries; repeat
Error message
gave up applying effects after {MAX_RETRIES} retries; repeated effect-state divergence on: {keys:?}. This implies multiple routes are fighting to write one of these files. What it means
Thrown by handle_apply_retry() in turbo-tasks after MAX_RETRIES (4) failed attempts to apply effects because the effect state keeps diverging. Effects are Turbopack's mechanism for persisting side outputs (e.g. written files) during strongly-consistent resolution; persistent divergence means two different computations/routes are repeatedly trying to write the same file(s) with different content.
Source
Thrown at turbopack/crates/turbo-tasks/src/effect.rs:635
/// `MAX_RETRIES`). Returns `Err` for terminal outcomes: a non-`Retry` error, or `Retry` after the
/// retry budget is exhausted.
fn handle_apply_retry(err: EffectsError, attempts: &mut usize) -> Result<()> {
const MAX_RETRIES: usize = 4; // chosen by a fair dice roll
match err {
EffectsError::Retry { keys } if *attempts < MAX_RETRIES => {
*attempts += 1;
// Warn on every retry after the first.
if *attempts > 1 {
tracing::warn!(
attempts = *attempts,
?keys,
"retrying effect application; this implies multiple routes are fighting to \
write one of these files",
);
}
Ok(())
}
EffectsError::Retry { keys } => anyhow::bail!(
"gave up applying effects after {MAX_RETRIES} retries; repeated effect-state \
divergence on: {keys:?}. This implies multiple routes are fighting to write one of \
these files."
),
e => Err(e.into()),
}
}
/// Build the deduped per-key indices into the captured slice. Detects per-key value-hash
/// conflicts. This is the eager half of effect deduplication — it inspects only the captured
/// effects themselves (no [`EffectStateStorage`] interaction) and is therefore safe to call
/// from inside a turbo-tasks task in [`take_effects`].
fn build_unique_keys(captured: &[Box<dyn CapturedEffect>]) -> UniqueKeys {
let mut by_key: FxHashMap<Box<[u8]>, usize> = FxHashMap::default();
for (idx, effect) in captured.iter().enumerate() {
match by_key.entry(effect.key()) {
hash_map::Entry::Vacant(entry) => {
entry.insert(idx);View on GitHub (pinned to 0ae8c72462)
Solutions
- Inspect the `keys` in the error to identify which file(s) are being fought over, then find which routes both emit them.
- Eliminate the collision: rename/differentiate the conflicting routes or assets so each file has a single producer.
- Update to the latest Turbopack/Next.js version — effect-handling bugs are actively fixed.
- If the keys are internal build artifacts, simplify the build graph (disable experimental features, reduce conflicting rewrites) to isolate the producer.
Defensive patterns
Strategy: retry
Prevention
- Avoid mapping multiple routes to the same output asset path.
- Keep the build graph simple; disable experimental features that may duplicate producers.
- Stay on the latest Next.js/Turbopack version to pick up effect-handling fixes.
- When you see the warning about 'routes fighting to write a file', investigate the keys immediately.
When it happens
Trigger: Two or more routes or chunks in a Turbopack build produce conflicting content for the same output file key, so each apply invalidates the other's state and the retry loop never converges within 4 attempts.
Common situations: Multiple pages/app routes accidentally mapped to the same output asset path; a misconfigured manifest or chunk-naming collision; a Turbopack bug in effect deduplication for shared assets; custom output structure causing filename clashes.
Related errors
- Default export is missing in {resource_path}
- Command failed: ${command} ${args.join(' ')} (exit ${code})
- Missing ${NEXT_BIN}. Build Next.js first (pnpm --filter=next
- Command failed: ${command} ${args.join(' ')} (exit ${code})
- Missing ${NEXT_BIN}. Build Next.js first (pnpm --filter=next
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/d12c9808cf8ea966.
Report an issue: GitHub.