errno no Python: entenda erros do sistema

Publicado em: 24/08/2026
Tempo de leitura: 6 minutos
Detailed view of programming code in a dark theme on a computer screen.

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.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ctypes no Python: use bibliotecas C

    Aprenda ctypes no Python para carregar bibliotecas C, definir tipos e ponteiros, gerenciar memória, callbacks, ABI e erros com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    24/08/2026
    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    expat no Python: parser XML de baixo nível

    Aprenda expat no Python para parsing XML de baixo nível, handlers, namespaces, erros e proteções contra amplificação e DoS.

    Ler mais

    Tempo de leitura: 5 minutos
    23/08/2026
    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ElementInclude no Python: use XInclude

    Aprenda ElementInclude no Python para usar XInclude com loaders seguros, base URL, profundidade máxima e bloqueio de caminhos externos.

    Ler mais

    Tempo de leitura: 5 minutos
    23/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    xmlreader no Python: controle parsers SAX

    Aprenda xmlreader no Python para configurar parsers SAX, InputSource, parsing incremental, atributos, locators e segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    23/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    saxutils no Python: utilitários para XML

    Aprenda saxutils no Python para escapar XML, preparar atributos, gerar documentos, criar filtros SAX e evitar erros de contexto.

    Ler mais

    Tempo de leitura: 6 minutos
    23/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pulldom no Python: DOM parcial para XML

    Aprenda pulldom no Python para processar XML por eventos, expandir apenas subárvores necessárias e reduzir memória com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    23/08/2026