Turbopack Rust panic: decodificando e corrigindo inner_of_uppers_lost_follower no next.js 16
Voltar para blog

Turbopack Rust panic: decodificando e corrigindo inner_of_uppers_lost_follower no next.js 16

07/06/2026 · 7 min · Desenvolvimento

Rust panic na inicialização do dev server#

Ambiente: Next.js 16.0.0, Turbopack habilitado, pnpm (versões 8.x ou 9.x recomendadas) como gerenciador de pacotes, Linux. Pré-requisitos do Node.js: O Next.js 16 requer Node.js 18.17+ (sendo altamente recomendado o uso de Node.js 20 LTS). Verifique o seu ambiente executando:

node --version
pnpm --version

Comando de inicialização:

NODE_OPTIONS='--max-old-space-size=4096' next dev -H 0.0.0.0

O servidor de desenvolvimento abortou durante a fase de bundling inicial com o seguinte output fatal no stderr:

thread 'tokio-runtime-worker' (862) panicked at
/build/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs:1420:17:
inner_of_uppers_lost_follower is not able to remove follower TaskId 17
(ProjectContainer::entrypoints) from TaskId 16 (EntrypointsOperation::new)
as they don't exist as upper or follower edges
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Error [TurbopackInternalError]: inner_of_uppers_lost_follower is not able to
remove follower TaskId 17 (ProjectContainer::entrypoints) from TaskId 16
(EntrypointsOperation::new) as they don't exist as upper or follower edges
at Object.resolveEntrypoints ...
at async DevServer.prepare ...

O erro não partiu do código da aplicação: nenhum arquivo .ts, .tsx ou .js do projeto foi mencionado como origem. O panic ocorreu dentro do próprio runtime do Turbopack, em código Rust.

Anatomia do panic: o que o erro realmente diz#

Decodificando a stack trace#

O Turbopack é escrito em Rust e usa um sistema de incremental computation chamado turbo-tasks. Este sistema mantém um grafo de dependências direcionado onde cada nó representa uma "task", a unidade de trabalho que pode ser uma operação de compilação de arquivo, resolução de imports, geração de output de bundle, etc.

O modelo de dados do grafo é o seguinte:

flowchart TD subgraph turbo-tasks["turbo-tasks: Grafo de Dependências"] T17["TaskId 17\nProjectContainer::entrypoints"] T16["TaskId 16\nEntrypointsOperation::new"] T15["TaskId 15\nModuleResolver"] T14["TaskId 14\nChunkBuilder"] T17 -->|"follower edge\n(invalidar quando mudar)"| T16 T15 -->|"follower edge"| T17 T16 -->|"upper edge"| T14 end PANIC["💥 PANIC\naggregation_update.rs:1420\nfollower edge não existe"] T16 -.->|"remove() retorna false"| PANIC style PANIC fill:#7f1d1d,color:#fca5a5 style T16 fill:#1e3a5f,color:#93c5fd style T17 fill:#1e3a5f,color:#93c5fd

Uma "follower edge" significa: "quando TaskId 17 (entrypoints do projeto) completar, notifique TaskId 16 (operação de entrypoints)". Esta é a mecânica de propagação de invalidação que torna o HMR tão rápido no Turbopack.

O que "inner_of_uppers_lost_follower" significa#

A função inner_of_uppers_lost_follower em aggregation_update.rs:1420 é parte do algoritmo de agregação de dependências, responsável por consolidar e propagar atualizações através do grafo quando um arquivo muda.

O panic ocorre na linha:

// aggregation_update.rs:1420
assert!(
inner_task.followers.remove(&upper_task_id),
"inner_of_uppers_lost_follower is not able to remove follower TaskId {} ({:?}) \
 from TaskId {} ({:?}) as they don't exist as upper or follower edges",
upper_task_id, ..., inner_task_id, ...
);

Tradução operacional: O engine Turbopack tentou remover uma borda de dependência entre dois nós do grafo (TaskId 17 → TaskId 16), mas essa borda não existia no estado atual do grafo. A invariante interna foi violada - o grafo está em estado inconsistente - e o Rust, que não faz "silent failures" em assertions, causou um panic.

Por que o estado fica inconsistente?#

Corrupções no turbo-tasks-backend ocorrem principalmente em dois cenários:

  1. Cache residual de versão anterior: A pasta .next contém serialização do estado do grafo de uma versão diferente do Turbopack. Ao atualizar o Next.js ou o pnpm e reusar o cache antigo, o grafo desserializado pode ter referências a TaskIds que não existem mais na versão nova.
  1. Bug de concorrência no tokio-runtime-worker: Múltiplos threads do runtime async do Rust (tokio) operando no grafo simultaneamente podem, em condições de race condition, produzir estado inconsistente. O prefixo thread 'tokio-runtime-worker' (862) no panic indica que o erro ocorreu em um worker thread do pool de threads async.

Solução 1 - reset do cache do turbopack (recomendada)#

1.1 verificação de cache corrompido#

Antes de prosseguir com a limpeza agressiva, você pode verificar se o cache do Next.js está presente, o tamanho que ocupa em disco e se existem travas de processo ativas que possam estar impedindo a invalidação automática do Turbopack:

# Verificar se há diretórios de cache estruturados
ls -la .next/cache/

# Analisar o espaço em disco ocupado pelo cache
du -sh .next/cache/

# Checar se existem arquivos de trava residuais
ls -la .next/cache/*.lock 2>/dev/null

# Confirmar se há processos fantasmas do Turbopack rodando em segundo plano
ps aux | grep -i turbopack

1.2 limpeza segura via next clean#

A remoção direta via rm -rf é eficaz, mas o Next.js disponibiliza um comando oficial chamado next clean. O next clean é preferível porque ele remove estritamente os artefatos de build gerados pelo framework (evitando apagar acidentalmente arquivos customizados que o desenvolvedor possa ter colocado manualmente na pasta .next):

# Opção oficial usando npx
npx next clean

# Caso use pnpm
pnpm next clean

1.3 remoção física multi-plataforma#

Caso precise deletar a pasta fisicamente por completo, execute o comando correspondente ao seu sistema operacional:

# Linux e macOS
rm -rf .next

# Windows (PowerShell com privilégios de Admin)
Remove-Item -Recurse -Force .next

# Windows (Command Prompt - CMD)
rmdir /s /q .next

# Alternativa Unix segura sem remover a pasta raiz
find .next -type f -delete && find .next -type d -empty -delete

O que este procedimento remove:

Após a remoção, o Turbopack reconstrói o grafo de computação do zero:

NODE_OPTIONS='--max-old-space-size=4096' pnpm dev

Verificando a resolução: O dev server deve iniciar e compilar as rotas iniciais sem disparar logs de TurbopackInternalError. Output esperado de sucesso:

  ▲ Next.js 16.0.0 (Turbopack)
  - Local:        http://localhost:3000
  - Network:      http://0.0.0.0:3000

 ✓ Starting...
 ✓ Ready in 2.4s

1.4 compatibilidade do pnpm#

O Next.js 16 recomenda a utilização de versões recentes do gerenciador pnpm (série 8.x ou 9.x). Verifique se o seu gerenciador atende a esses requisitos ou atualize-o para evitar incompatibilidades de resolução de dependências recursivas:

# Checar versão atual
pnpm --version

# Atualizar globalmente para a versão estável 9.x
npm install -g pnpm@9

1.5 prevenção de cache em Docker e CI/CD#

Em pipelines automatizados de Integração Contínua e na geração de imagens Docker, caches antigos persistidos de builds locais ou passadas são as maiores fontes de panics e falhas de compilação.

Dockerfile (Hardening de Build):

# Antes de rodar a instalação e o build de produção, garanta a limpeza
RUN rm -rf .next || true
# Ou utilize a CLI oficial
RUN npx next clean || true
RUN pnpm build

GitHub Actions Workflow (ci.yml):

# Passo explícito para invalidar caches anteriores do Next.js
- name: Clean Next.js cache
  run: rm -rf .next || npx next clean

- name: Start build
  run: pnpm build

1.6 interferência de ides e file watchers#

IDEs como VS Code ou a suite JetBrains (IntelliJ, WebStorm) ativam monitoradores de arquivos (file watchers) e servidores de linguagem TypeScript recursivos. Se esses watchers indexarem a pasta .next enquanto o dev server do Turbopack estiver gravando no cache, pode ocorrer conflito de I/O bloqueante (locks de arquivo), gerando o panic.

Solução: Exclua a pasta .next da indexação do VS Code adicionando a seguinte configuração em .vscode/settings.json:

{
  "files.watcherExclude": {
    "**/.next/**": true,
    "**/node_modules/**": true
  }
}

Por que o cache do next.js fica corrompido?#

# Causas comuns que produzem o panic pós-reinstalação:
pnpm update next           → Nova versão do Turbopack com schema de cache diferente
rm -rf node_modules && bun install  → Muda o runtime, grafo serializado incompatível
git pull (com mudanças em tsconfig.json, next.config.js)  → Invalidação incompleta

Para prevenir recorrências de desenvolvimento, adicione scripts robustos no package.json:

{
  "scripts": {
    "dev": "next dev --turbo",
    "clean": "next clean",
    "dev:clean": "next clean && next dev --turbo",
    "build:clean": "next clean && next build"
  }
}

Solução 2 - fallback para webpack (continuidade de desenvolvimento)#

Se o panic persistir após múltiplas limpezas de cache (o que indica um bug específico da versão), a saída imediata é remover o Turbopack da equation:

package.json - antes:

{
  "scripts": {
"dev": "next dev --turbo"
  }
}

package.json - depois:

{
  "scripts": {
"dev": "next dev"
  }
}

Ou, se o Turbopack foi habilitado via next.config.js:

// next.config.js - ANTES (Turbopack ativo)
const nextConfig = {
  experimental: {
turbo: {
  rules: { /* ... */ }
}
  }
}

// next.config.js - DEPOIS (Webpack como padrão)
const nextConfig = {
  // experimental.turbo removido
}

Trade-offs do fallback:

AspectoTurbopackWebpack fallback
HMR latência~150ms~800ms - 2.4s
RAM em idle~1.3 GB~2.8 GB
Estabilidade em major release⚠️ Bugs esperados inicialmente✅ Mais estável
Acesso a features Next.js 16✅ Total✅ Total

O fallback para Webpack não perde nenhuma feature do Next.js 16: ele apenas usa o compilador mais antigo. O desenvolvimento continua normalmente enquanto o team da Vercel patcha o bug.

Solução 3 - atualização para versão canary#

Se o panic for um bug já identificado e corrigido nos nightly builds do Next.js, o caminho mais rápido para ter o Turbopack estável é a versão canary:

# Com pnpm
pnpm update next@canary react@canary react-dom@canary

# Com bun
bun update next@canary react@canary react-dom@canary

Verificando a versão canary instalada:

pnpm list next
# └─ next 16.0.1-canary.15 (ou superior)

Quando usar o canary vs. aguardar o stable:

CritérioCanaryAguardar Stable
Projeto em MVP / desenvolvimento✅ Aceitável✅ Seguro
Projeto em produção❌ Arriscado✅ Obrigatório
Erro de build crítico bloqueante✅ Testar canary-
Time com capacidade de debug✅ Canary útil-

Monitorando o repositório do Next.js para o patch:

# Buscar issues relacionados no GitHub CLI (se instalado)
gh issue list --repo vercel/next.js --search "inner_of_uppers_lost_follower"

# Ou acompanhar o CHANGELOG da versão canary
curl -s https://raw.githubusercontent.com/vercel/next.js/canary/packages/next/CHANGELOG.md | grep -A 5 "turbopack"

3.1 reportando e criando uma issue no GitHub#

Caso o panic persista e nenhuma issue correspondente seja encontrada, é essencial reportar o bug fornecendo as informações corretas de diagnóstico para o time do Next.js. Você pode abrir a issue via browser ou diretamente pelo GitHub CLI:

# Criar issue detalhada via GitHub CLI usando metadados do ambiente
gh issue create --repo vercel/next.js \
  --title "Turbopack panic: inner_of_uppers_lost_follower in Next.js 16" \
  --body "## Ambiente de Execução
- Next.js: \$(pnpm list next 2>/dev/null | grep next | awk '{print \$2}' || echo '16.0.0')
- Node.js: \$(node --version)
- SO: \$(uname -a)
- pnpm: \$(pnpm --version)

## Stack trace de panic do Rust
\`\`\`
\$(cat /tmp/turbopack-panic.log 2>/dev/null || echo 'thread tokio-runtime-worker panicked at inner_of_uppers_lost_follower')
\`\`\`

## Passos para reproduzir
1. Habilitar o modo experimental do Turbopack (\`--turbo\`) no Next.js 16.
2. Executar o dev server com \`pnpm dev\`.
3. Alterar dependências ou atualizar imports de entrypoints rapidamente durante o HMR."

# Ou abrir o fluxo diretamente na interface web do repositório
gh issue create --repo vercel/next.js --web

Habilitando o backtrace e monitoramento avançado#

6.1 backtrace do Rust#

Se você precisa reportar o bug para o repositório oficial do Next.js ou entender a origem exata da quebra lógica, a variável de ambiente RUST_BACKTRACE=1 revela a stack trace completa interna do Rust:

RUST_BACKTRACE=1 NODE_OPTIONS='--max-old-space-size=4096' pnpm dev 2>&1 | tee /tmp/turbopack-panic.log

A saída estruturada resultante trará todos os frames de chamada Rust:

stack backtrace:
   0: rust_begin_unwind
         at /rustc/.../library/std/src/panicking.rs:647:5
   1: core::panicking::panic_fmt
         at /rustc/.../library/core/src/panicking.rs:72:14
   2: turbo_tasks_backend::backend::operation::aggregation_update::inner_of_uppers_lost_follower
         at /build/turbopack/crates/turbo-tasks-backend/src/backend/operation/aggregation_update.rs:1420:17
   3: turbo_tasks_backend::backend::operation::aggregation_update::AggregationUpdateQueue::process
         at .../aggregation_update.rs:890:13
   4: turbo_tasks_backend::backend::TurboTasksBackend::run_backend_job
         at .../mod.rs:421:9
   ...

6.2 monitoramento de consumo de memória#

Estouros de recursos durante a transpilação e watch do Turbopack podem ser identificados por meio do monitoramento da memória RAM. Utilize os seguintes comandos para isolar processos Node.js:

# Listar processos Node.js ativos com porcentagem de CPU/Memória e tamanho em KB
ps aux | grep node | awk '{print "PID: "$2" | CPU: "$3"% | RAM: "$4"% ("$6" KB) | Comando: "$11}'

# Monitorar em tempo real os subprocessos associados ao Next.js
htop -p $(pgrep -f "next dev" | paste -sd,)

# Ativar console de inspeção do Node para análise de perfil de heap
NODE_OPTIONS='--max-old-space-size=4096 --inspect' pnpm dev

6.3 script de diagnóstico completo (diagnose-turbopack.sh)#

Para facilitar a triagem de problemas de ambiente em servidores locais ou containers, crie um script local diagnose-turbopack.sh:

#!/bin/bash
# diagnose-turbopack.sh - Diagnóstico de dependências e cache do Turbopack
set -euo pipefail

echo "==========================================="
echo "  DIAGNÓSTICO DO MOTOR TURBOPACK / NEXT.JS"
echo "==========================================="
echo ""

echo "[1] Verificando Versões do Sistema:"
echo "    Node.js: \$(node --version)"
if command -v pnpm >/dev/null 2>&1; then
    echo "    pnpm:    \$(pnpm --version)"
    echo "    Next.js: \$(pnpm list next 2>/dev/null | grep ' next ' | awk '{print \$2}' || echo 'Não listado')"
else
    echo "    pnpm:    Não instalado"
    echo "    Next.js: (instale o pnpm para verificar a versão do pacote)"
fi
echo "    Kernel:  \$(uname -s) \$(uname -r)"
echo ""

echo "[2] Verificando Estado da Pasta .next:"
if [ -d ".next" ]; then
    echo "    Existe:   Sim"
    echo "    Tamanho:  \$(du -sh .next 2>/dev/null | awk '{print \$1}')"
    echo "    Modificado em: \$(stat -c %y .next 2>/dev/null || stat -f %Sm .next 2>/dev/null)"
else
    echo "    Existe:   Não"
fi
echo ""

echo "[3] Processos do Next/Turbopack Ativos:"
PROCS=\$(ps aux | grep -E "next|turbopack" | grep -v grep || true)
if [ -n "\$PROCS" ]; then
    echo "\$PROCS"
else
    echo "    Nenhum processo encontrado rodando."
fi
echo ""

echo "[4] Capacidade de Memória RAM Livre:"
if command -v free &>/dev/null; then
    free -h | head -2
else
    echo "    Comando 'free' não disponível (SO sem suporte)."
fi
echo ""

echo "[5] Permissões das Pastas Internas:"
if [ -d ".next" ]; then
    ls -la .next/ | head -n 5
fi

echo "==========================================="
echo "         FIM DO DIAGNÓSTICO DO HOST"
echo "==========================================="

Resumo de decisão: qual solução aplicar#

flowchart TD START["💥 Rust Panic:\ninner_of_uppers_lost_follower"] --> A{"✅ Node.js\n18.17 ou superior?"} A -->|Não| A1["📦 Instalar\nNode.js 20 LTS"] A -->|Sim| B["pnpm next clean\n(ou rm -rf .next)"] B --> C{"pnpm dev\nResolveu?"} C -->|Sim| C1["✅ Cache corrompido\nAdicionar dev:clean"] C -->|Não| D["Fechar IDE\nSuspender watchers"] D --> E{"Resolveu?"} E -->|Sim| E1["✅ Conflito de I/O\nda IDE resolvido"] E -->|Não| F["Remover\n--turbo flag"] F --> G{"Resolveu?"} G -->|Sim| G1["✅ Bug de versão\nUsar Webpack"] G -->|Não| H["pnpm update\nnext@canary"] H --> I{"Resolveu?"} I -->|Sim| I1["✅ Bug corrigido\nno canary"] I -->|Não| J["🐛 Criar issue no GitHub\ncom RUST_BACKTRACE=1"] style START fill:#7f1d1d,color:#fca5a5 style C1 fill:#14532d,color:#86efac style E1 fill:#14532d,color:#86efac style G1 fill:#14532d,color:#86efac style I1 fill:#14532d,color:#86efac style J fill:#78350f,color:#fde68a

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

CC BY-NC

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários