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

    Desenvolvedor configurando servidor HTTPS e certificado TLS com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crie servidor HTTPS local no Python

    Aprenda HTTPSServer no Python para servir HTTPS localmente, configurar certificados, usar threads e entender limites de segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    08/10/2026
    Arquivos protegidos representando extração segura de TAR com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extraia TAR com segurança

    Aprenda tarfile extraction_filter no Python para extrair arquivos TAR com validação, segurança e controle de caminhos.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python exibindo avisos controlados com catch_warnings
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: capture warnings em testes Python

    Aprenda catch_warnings no Python para capturar, testar e controlar avisos com filtros específicos e segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python representando referências persistentes do pickle
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serialize referências externas

    Aprenda pickle persistent_id no Python para serializar referências externas com IDs estáveis, validação, segurança e compatibilidade.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binário representando buffers e memória no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: conte valores sem copiar buffers

    Aprenda memoryview.count no Python para contar bytes e valores em buffers sem cópias, com formatos, limites e boas práticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python com anotações de tipos
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evite imports circulares em anotações

    Aprenda annotationlib no Python para ler anotações adiadas, evitar imports circulares e criar ferramentas de introspecção seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026