O módulo errno reúne os códigos simbólicos usados pelo sistema operacional para representar falhas de arquivos, processos, sockets, dispositivos e chamadas nativas. Em vez de comparar números mágicos como 2, 13 ou 111, o código pode usar nomes como ENOENT, EACCES e ECONNREFUSED.
No Python moderno, muitos desses códigos já são convertidos em subclasses específicas de OSError, como FileNotFoundError, PermissionError, BlockingIOError e ConnectionRefusedError. Mesmo assim, errno continua importante em integração com APIs C, operações não bloqueantes e tratamento portátil de erros menos comuns.
Por que usar nomes simbólicos
O valor numérico de um erro pode variar entre sistemas. O nome simbólico expressa a intenção e melhora a portabilidade.
import errno
try:
with open("config.ini", "rb") as arquivo:
dados = arquivo.read()
except OSError as exc:
if exc.errno == errno.ENOENT:
print("Arquivo não encontrado")
else:
raise
Quando existe uma exceção específica, ela costuma ser mais clara:
try:
with open("config.ini", "rb") as arquivo:
dados = arquivo.read()
except FileNotFoundError:
print("Arquivo não encontrado")
Use errno quando vários códigos compartilham a mesma classe ou quando uma biblioteca nativa entrega apenas o inteiro.
OSError e o atributo errno
OSError normalmente oferece errno, strerror, filename e, em algumas operações, filename2. Nem toda instância terá todos os campos preenchidos, portanto use getattr() quando a origem for incerta.
try:
origem.replace(destino)
except OSError as exc:
print("código:", exc.errno)
print("mensagem:", exc.strerror)
print("arquivo:", exc.filename)
Não tome decisões de negócio com base no texto de strerror. A mensagem pode variar por idioma, plataforma e versão. Compare o código ou a classe da exceção.
Converter número em nome
errno.errorcode mapeia valores numéricos para nomes simbólicos disponíveis no sistema atual.
import errno
codigo = errno.EACCES
nome = errno.errorcode.get(codigo, "ERRO_DESCONHECIDO")
print(codigo, nome)
Nem todo símbolo existe em todas as plataformas. Para código multiplataforma, consulte com hasattr(errno, "NOME") ou use getattr() com fallback.
Converter código em mensagem
Use os.strerror() para obter uma descrição textual do sistema.
import errno
import os
print(os.strerror(errno.ENOSPC))
A mensagem é adequada para logs e interfaces, mas não para comparações lógicas. Em uma API, prefira retornar um código interno estável e uma mensagem localizada separadamente.
Erros comuns de arquivos
Alguns códigos frequentes são:
ENOENT para arquivo ou diretório inexistente; EACCES ou EPERM para permissão negada; EEXIST para destino já existente; ENOTDIR quando um componente deveria ser diretório; EISDIR quando uma operação espera arquivo; ENOSPC quando não há espaço; EROFS em filesystem somente leitura; e EXDEV ao tentar certas operações entre dispositivos.
Para arquivos temporários e escrita atômica, veja tempfile no Python. Mesmo um fluxo correto deve tratar falta de espaço, permissões e renomeação entre volumes.
EXDEV e movimentação entre discos
Path.rename() e os.rename() podem falhar com EXDEV quando origem e destino estão em filesystems diferentes. Nesse caso, uma aplicação pode copiar, validar e remover a origem, desde que essa semântica seja aceitável.
import errno
import shutil
try:
origem.replace(destino)
except OSError as exc:
if exc.errno != errno.EXDEV:
raise
shutil.copy2(origem, destino)
origem.unlink()
Essa alternativa não tem exatamente a mesma atomicidade. Faça verificação de integridade e trate falhas intermediárias.
Operações não bloqueantes
EAGAIN, EWOULDBLOCK, EINPROGRESS e EALREADY aparecem em sockets e descritores não bloqueantes. Muitos são mapeados para BlockingIOError.
import errno
try:
dados = socket.recv(4096)
except BlockingIOError as exc:
if exc.errno in {errno.EAGAIN, errno.EWOULDBLOCK}:
dados = None
else:
raise
Em algumas plataformas, EAGAIN e EWOULDBLOCK têm o mesmo valor; em outras, devem ser considerados separadamente. Não use loops ocupados. Espere prontidão com selectors ou select.
Erros de rede
Entre os códigos mais úteis estão ECONNREFUSED, ECONNRESET, ECONNABORTED, ETIMEDOUT, EHOSTUNREACH, ENETUNREACH, EADDRINUSE e EADDRNOTAVAIL.
O guia de socketserver no Python aborda servidores, concorrência e encerramento. Para HTTP, urllib.error no Python diferencia respostas HTTP de falhas de transporte.
Broken pipe
EPIPE ocorre quando um processo escreve em pipe ou socket cujo leitor fechou a conexão. Python normalmente gera BrokenPipeError.
try:
conexao.sendall(payload)
except BrokenPipeError:
fechar_sessao()
Não continue tentando enviar indefinidamente. Remova o descritor do loop, libere recursos e registre a falha de forma limitada.
Chamadas interrompidas
EINTR representa chamada interrompida por sinal. Desde o PEP 475, várias APIs do Python repetem automaticamente a chamada quando o handler não levanta exceção. Ainda assim, bibliotecas nativas e algumas operações podem expor InterruptedError.
while True:
try:
return operacao()
except InterruptedError:
continue
Repita somente operações seguras e idempotentes. Uma chamada pode ter causado efeitos parciais antes da interrupção.
Integração com ctypes
O conjunto anterior, ctypes no Python, mostrou use_errno=True. Essa opção mantém uma cópia thread-local do erro nativo para leitura por ctypes.get_errno().
import errno
import os
from ctypes import CDLL, get_errno
lib = CDLL("libexemplo.so", use_errno=True)
resultado = lib.abrir_recurso()
if resultado == -1:
codigo = get_errno()
if codigo == errno.EACCES:
raise PermissionError(codigo, os.strerror(codigo))
raise OSError(codigo, os.strerror(codigo))
Leia o código imediatamente após a função que falhou. Outra chamada nativa pode substituí-lo.
Portabilidade
A lista de símbolos é específica do sistema. Linux, macOS, BSD, Windows e WASI não oferecem exatamente os mesmos nomes. O dicionário errno.errorcode mostra apenas valores disponíveis no ambiente atual.
import errno
EDQUOT = getattr(errno, "EDQUOT", None)
if EDQUOT is not None:
print("Quota de disco pode ser identificada nesta plataforma")
Ao serializar erros para outro sistema, não envie apenas o inteiro. Envie um identificador de aplicação e, opcionalmente, o nome simbólico e a plataforma.
Não capturar OSError de forma ampla
Um bloco que converte qualquer OSError em “arquivo não existe” esconde falta de permissão, disco cheio e corrupção.
try:
carregar()
except FileNotFoundError:
criar_padrao()
Capture somente a condição que você realmente sabe resolver. Relevante também para tentativas de retry: ENOSPC não melhora com repetição imediata, enquanto algumas falhas temporárias podem justificar backoff.
Classificar erros para retry
Crie uma política explícita.
TRANSITORIOS = {
errno.EAGAIN,
errno.EINTR,
errno.ETIMEDOUT,
}
def pode_repetir(exc: OSError) -> bool:
return exc.errno in TRANSITORIOS
A decisão depende da operação. Repetir um POST, uma escrita ou uma exclusão pode duplicar efeitos. Combine o código com idempotência, número de tentativas e atraso exponencial.
Logs estruturados
Registre classe da exceção, errno, nome simbólico, operação, recurso redigido e plataforma.
def erro_para_log(exc: OSError) -> dict:
return {
"tipo": type(exc).__name__,
"errno": exc.errno,
"simbolo": errno.errorcode.get(exc.errno),
"mensagem": exc.strerror,
}
Não inclua credenciais, conteúdo de arquivos ou caminhos sensíveis sem necessidade.
Testes recomendados
Teste arquivo inexistente, permissão negada, destino existente, diretório usado como arquivo, filesystem somente leitura, espaço esgotado, socket recusado, timeout, conexão resetada, operação não bloqueante e símbolos ausentes na plataforma.
Em testes unitários, construa OSError com códigos conhecidos, mas mantenha alguns testes de integração reais, porque o comportamento pode variar por sistema.
Erros comuns
Os erros mais frequentes são comparar a mensagem textual, usar números mágicos, presumir que todo símbolo existe, capturar qualquer OSError, repetir operações não idempotentes, ler errno tarde demais depois de uma chamada C e expor códigos internos diretamente como contrato público.
Conclusão
errno transforma códigos numéricos do sistema em nomes legíveis e portáveis dentro dos limites de cada plataforma. Ele complementa as subclasses modernas de OSError e é especialmente importante para I/O não bloqueante e integração nativa.
Prefira exceções específicas quando possível, compare símbolos em vez de mensagens e aplique uma política de retry consciente. Consulte a documentação oficial de errno e a documentação oficial de OSError.







