O bug que corrige sozinho o arquivo, mas não o e-mail que ele gera
Um sistema meu estava mandando e-mail em português com acentuação errada. Não era acento faltando, era acento trocado: "operação" virava "operação" em alguns lugares e simplesmente sumia em outros. O arquivo CSV de onde os dados vinham parecia correto quando eu abria ele. O bug só aparecia na saída final.
A causa não era o arquivo. Era a leitura dele.
O sintoma
O script lia um CSV com encoding="latin1" e escrevia de volta com encoding="latin1". Isso rodava há meses sem erro, sem exceção, sem log estranho. Só que o arquivo, na verdade, sempre foi UTF-8.
Por que isso nunca quebrou? Porque UTF-8 lido como Latin-1 é um round-trip estável. Cada caractere acentuado em UTF-8 ocupa dois bytes. Latin-1 é uma tabela de um byte só, mas cobre justamente a faixa 0x80-0xFF, então cada um daqueles dois bytes vira um caractere Latin-1 válido, só que errado (tipo "Ã" e "§" no lugar de "ç"). Escrever esses dois caracteres de volta como Latin-1 produz exatamente os mesmos dois bytes originais. O arquivo nunca corrompe. Ele só mente pra quem olha.
Onde o estrago aparece
O estrago só ficou visível quando esse texto mal lido saiu para um lugar que realmente decodifica como UTF-8: um prompt de LLM, um log em UTF-8, um e-mail. Aí os dois bytes viram os dois caracteres errados de verdade, visíveis, feios.
Ler raw.decode('latin1') nunca lança exceção, mesmo com dado sujo. Isso é o motivo do bug ter sobrevivido tanto tempo: não existe erro pra investigar, só resultado sutilmente errado.
O diagnóstico que separou hipótese de fato
Antes de mexer em qualquer script, decodifiquei o arquivo inteiro como UTF-8 puro, sem passar por nenhum código do sistema:
raw = open("dados.csv", "rb").read()
texto = raw.decode("utf-8") # se isso não lançar erro, o arquivo já é UTF-8
Decodificou limpo, zero exceção, em um arquivo de mais de cem mil caracteres. Isso provou duas coisas de uma vez: o arquivo sempre foi UTF-8 correto, e o problema inteiro estava nos scripts que liam ele errado. Não havia dado real pra recuperar ou consertar, só a leitura errada pra corrigir.
A correção
Trocar encoding="latin1" por encoding="utf-8" em cada ponto que abria aquele arquivo específico. Nada mais. Nenhuma linha de dado foi reescrita.
O jeito de confirmar que a correção funcionou não foi só rodar sem erro. Foi gerar conteúdo de verdade a partir do fluxo completo, com vocabulário que nunca tinha passado por ali antes, e ler o resultado num lugar que expõe o problema visualmente, no caso, o corpo de um e-mail de teste.
A lição que fica
Round-trip estável esconde bug. Se ler errado e escrever errado sempre voltam pro mesmo byte, o sistema parece saudável em todo teste que só olha o arquivo. O bug só aparece no consumidor final, e só se alguém realmente olhar o resultado, não só o código de saída do processo.
Antes de assumir que um dado está corrompido, vale testar a hipótese mais simples primeiro: talvez o dado esteja certo, e a leitura é que está errada.
Nayara Martins, desenvolvedora de sistemas sob medida em Assis, SP. Mais em prospectia.space.