Você perde o SSH no meio de um turno, volta e manda codex resume. Em vez da conversa, aparece uma linha seca: thread 019a4c1e-... already has an active writer. A thread não corrompeu e nada foi perdido. O Codex só está dizendo que outro processo continua com o direito de escrever nela.
É um erro de coordenação, não de conta nem de modelo. Tem causa conhecida, dono identificável e comando para resolver. Abaixo está o mecanismo, como achar o processo que segura a thread e o que fazer quando ele está em outra máquina.
O que significa "already has an active writer"?
O Codex permite um único escritor por thread, e esse escritor é garantido por um lock de arquivo do sistema operacional. Cada thread tem o seu: $CODEX_HOME/thread-writer-locks/<thread_id>.lock, com ~/.codex como padrão quando CODEX_HOME não está definido.
A tentativa de pegar o lock é não bloqueante. Quem chega segundo não espera a vez, recebe o erro na hora:
thread 019a4c1e-... already has an active writer
O caminho está explícito na fonte: o processo tenta try_lock no arquivo, e se o retorno for WouldBlock devolve exatamente essa mensagem (codex-rs/rollout/src/writer_lock.rs). Não é timeout de rede, não é cota, não é problema de login. É uma trava local que alguém ainda está segurando.
Por que o lock continua preso depois que eu fecho o terminal?
Porque o processo não morreu. Fechar a janela do terminal, perder a conexão SSH ou suspender com Ctrl+Z não encerra o Codex, e o lock só cai quando o processo termina de verdade.
| Situação | Quem fica com a thread | Onde está relatado |
|---|---|---|
| Queda de SSH com o TUI ocioso | O processo do TUI que ficou órfão no servidor | openai/codex #44063 |
| Thread aberta no app desktop e no CLI | O desktop, que abriu a thread primeiro | openai/codex #37403 |
| Thread vista no app do iOS via Remote Control | O daemon do app-server que serve o Remote Control | openai/codex #44449 |
Os três casos têm o mesmo formato: uma sessão antiga que ninguém encerrou. Nenhum deles exige reinstalar nada.
Como descobrir qual processo está segurando a thread?
O id da thread está na própria mensagem de erro. Com ele, aponte o lsof para o arquivo de lock correspondente:
lsof ~/.codex/thread-writer-locks/<thread_id>.lock
A saída traz o PID na segunda coluna:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 48213 mafra 23u REG 0,45 0 912 /home/mafra/.codex/thread-writer-locks/019a4c1e-....lock
Se o seu CODEX_HOME aponta para outro diretório, troque o caminho por $CODEX_HOME/thread-writer-locks/. O fuser -v no mesmo arquivo dá a mesma resposta quando o lsof não está instalado.
Como liberar a thread sem perder o histórico?
Encerre o processo que segura o lock e retome a sessão:
kill 48213
codex resume 019a4c1e-...
Não precisa apagar o arquivo .lock. O lock pertence ao sistema operacional e é liberado no instante em que o processo termina. Apagar o arquivo à mão cria um segundo problema: o processo antigo continua vivo e escrevendo na mesma thread, então você passa a ter dois escritores no mesmo rollout, que é exatamente o que o lock existia para impedir.
Se o dono do lock for o daemon do app-server, use o comando dele em vez do kill:
codex app-server daemon stop
E quando o processo está em outra máquina?
Aí você não tem como matar nada. O que dá para fazer é ler a thread: nas versões recentes do TUI, quando o resume esbarra no lock, a conversa abre em modo leitura, com o campo de entrada desabilitado, em vez de simplesmente falhar.
Nesse modo, a tecla f cria uma cópia da thread sem pedir o lock da original. A cópia recebe um id novo, leva o histórico junto e aceita escrita normalmente. É o caminho para continuar o trabalho quando a máquina que segura a thread não está na sua mão.
Vale saber o que isso custa: a thread original continua presa, e a cópia passa a ser a conversa viva. Se depois você recuperar acesso à máquina, encerre o processo antigo para não terminar com duas linhas de histórico divergentes.
Como evitar que o lock volte a travar a thread?
Uma thread, um cliente. O lock existe porque duas superfícies escrevendo na mesma conversa produzem histórico inconsistente, então a regra prática é não abrir a mesma thread em dois lugares ao mesmo tempo.
- Antes de retomar no CLI, feche o app desktop que estava com a thread aberta.
- Ao sair de uma sessão remota, encerre o Codex com
/exitantes de derrubar o SSH. Fechar o terminal não encerra o processo. - Para trabalho paralelo, use uma cópia da thread em vez de duas janelas na mesma sessão.
- Se você usa Remote Control, confira se a thread não ficou aberta no app do celular antes de retomar no desktop.
Perguntas rápidas
Apagar o arquivo .lock resolve?
Não. O lock é do processo, não do arquivo. Apagar o arquivo com o dono ainda vivo deixa dois escritores na mesma thread, que é o problema que o lock evita.
O erro aparece em uma thread só e as outras funcionam. Por quê?
Porque o lock é por thread, não por instalação. Uma sessão órfã trava apenas aquela conversa, e o resto do Codex segue normal.
Isso é bug do meu ambiente?
Não necessariamente. Os relatos abertos no repositório mostram o mesmo comportamento em Linux com SSH, em macOS com desktop e CLI, e no Remote Control com iOS. É coordenação de thread entre superfícies, não configuração quebrada.
Se o motivo de você manter a mesma thread em três clientes é revezar para não estourar cota, o caminho mais curto é uma CLI só. A Verboo Code entrega token ilimitado e troca de modelo com /model, sem fatura por token, então não existe razão para dois clientes na mesma sessão. Conhecer a Verboo Code.



