Python errno: Understand System Errors

Published on: August 24, 2026
Reading time: 4 minutes
A developer typing code on a laptop with a Python book beside in an office.

The errno module exposes symbolic names for operating-system error codes used by files, processes, sockets, devices, and native calls. Instead of comparing unexplained integers such as 2, 13, or 111, code can use names such as ENOENT, EACCES, and ECONNREFUSED.

Modern Python maps many codes to specific OSError subclasses, including FileNotFoundError, PermissionError, BlockingIOError, and ConnectionRefusedError. The module remains important for native integration, non-blocking I/O, and portable handling of less common conditions.

Why symbolic names matter

Numeric values may differ between operating systems. A symbolic name documents the condition and improves portability.

import errno

try:
    with open("config.ini", "rb") as file:
        data = file.read()
except OSError as exc:
    if exc.errno == errno.ENOENT:
        print("File was not found")
    else:
        raise

When Python provides a specific exception, that form is usually clearer:

try:
    with open("config.ini", "rb") as file:
        data = file.read()
except FileNotFoundError:
    print("File was not found")

Use errno when several codes map to one exception class or when a native library returns only an integer.

OSError attributes

OSError commonly provides errno, strerror, filename, and sometimes filename2. Not every instance has complete values, so use getattr() when the source is uncertain.

try:
    source.replace(destination)
except OSError as exc:
    print("code:", exc.errno)
    print("message:", exc.strerror)
    print("file:", exc.filename)

Do not drive application logic from strerror. Text varies by locale, platform, and operating-system version. Compare the exception type or numeric code.

Convert a number to a symbolic name

errno.errorcode maps available numeric values to their names.

import errno

code = errno.EACCES
name = errno.errorcode.get(code, "UNKNOWN_ERROR")
print(code, name)

Not every name exists on every platform. Use hasattr() or getattr() when supporting several systems.

Convert a code to text

os.strerror() returns the system message associated with a numeric code.

import errno
import os

print(os.strerror(errno.ENOSPC))

The text is useful for logs and interfaces, but not as a stable API contract. Return an application-defined error identifier separately from a localized description.

Common file errors

Frequently encountered values include ENOENT for a missing path, EACCES or EPERM for denied access, EEXIST for an existing destination, ENOTDIR when a component is not a directory, EISDIR when a file was expected, ENOSPC for a full filesystem, EROFS for read-only storage, and EXDEV for operations that cross devices.

For safer temporary files and atomic replacement patterns, see Python tempfile. Correct code must still handle permission failures, full disks, and cross-volume operations.

EXDEV across filesystems

Path.rename() and os.rename() may fail with EXDEV when source and destination are located on different filesystems. An application can copy, verify, and remove the source when that weaker semantic is acceptable.

import errno
import shutil

try:
    source.replace(destination)
except OSError as exc:
    if exc.errno != errno.EXDEV:
        raise
    shutil.copy2(source, destination)
    source.unlink()

The fallback is not equivalent to an atomic rename. Add integrity checks and cleanup for partial failures.

Non-blocking operations

EAGAIN, EWOULDBLOCK, EINPROGRESS, and EALREADY appear with non-blocking sockets and file descriptors. Python often exposes them through BlockingIOError.

import errno

try:
    data = sock.recv(4096)
except BlockingIOError as exc:
    if exc.errno in {errno.EAGAIN, errno.EWOULDBLOCK}:
        data = None
    else:
        raise

On some platforms EAGAIN and EWOULDBLOCK share a value. Do not busy-loop; wait for readiness with selectors or select.

Network errors

Important networking values include ECONNREFUSED, ECONNRESET, ECONNABORTED, ETIMEDOUT, EHOSTUNREACH, ENETUNREACH, EADDRINUSE, and EADDRNOTAVAIL.

The guide to Python socketserver covers server loops, concurrency, and shutdown. For HTTP clients, Python urllib.error separates HTTP responses from transport failures.

Broken pipes

EPIPE occurs when a process writes to a pipe or socket whose reader has closed. Python normally raises BrokenPipeError.

try:
    connection.sendall(payload)
except BrokenPipeError:
    close_session()

Stop sending, remove the descriptor from the event loop, release resources, and record a bounded diagnostic.

Interrupted system calls

EINTR means a system call was interrupted by a signal. Since PEP 475, many Python APIs retry automatically when the signal handler does not raise. Native libraries and some operations may still expose InterruptedError.

while True:
    try:
        return operation()
    except InterruptedError:
        continue

Retry only when the operation is safe. A call may have performed partial work before interruption.

Integration with ctypes

The previous guide, Python ctypes, used use_errno=True. This makes ctypes preserve a thread-local copy that can be read with get_errno().

import errno
import os
from ctypes import CDLL, get_errno

lib = CDLL("libexample.so", use_errno=True)
result = lib.open_resource()

if result == -1:
    code = get_errno()
    if code == errno.EACCES:
        raise PermissionError(code, os.strerror(code))
    raise OSError(code, os.strerror(code))

Read the code immediately after the failing native function. Another native call can overwrite it.

Platform differences

Linux, macOS, BSD, Windows, and WASI expose different subsets. errno.errorcode reflects the current environment.

import errno

quota_code = getattr(errno, "EDQUOT", None)
if quota_code is not None:
    print("Disk quota failures can be identified")

When sending an error to another service, do not transmit only the integer. Include an application-defined code and optionally the symbolic name and platform.

Avoid broad OSError recovery

Converting every OSError into “file does not exist” hides permission errors, storage exhaustion, device failures, and corrupted paths.

try:
    load_configuration()
except FileNotFoundError:
    create_default_configuration()

Catch only conditions your code can resolve. The same applies to retry logic: a full filesystem will not improve after an immediate retry, while some transient network conditions may justify backoff.

Classify retryable failures

TRANSIENT = {
    errno.EAGAIN,
    errno.EINTR,
    errno.ETIMEDOUT,
}

def can_retry(exc: OSError) -> bool:
    return exc.errno in TRANSIENT

The decision also depends on idempotency. Retrying a write, payment request, deletion, or POST may duplicate effects. Combine codes with operation semantics, attempt limits, jitter, and exponential backoff.

Structured logging

def error_for_log(exc: OSError) -> dict:
    return {
        "type": type(exc).__name__,
        "errno": exc.errno,
        "symbol": errno.errorcode.get(exc.errno),
        "message": exc.strerror,
    }

Include the operation and a redacted resource identifier, not credentials or full sensitive paths.

Test missing files, denied access, existing destinations, directory-versus-file mismatches, read-only storage, full disks, refused sockets, timeouts, reset connections, non-blocking operations, and symbols absent from the current platform.

Unit tests may construct OSError instances with known values, but keep some real integration tests because mappings and behavior vary by operating system.

Common mistakes

Common failures include comparing localized messages, using magic numbers, assuming every symbol exists, catching every OSError, retrying non-idempotent operations, reading native errno too late, and exposing operating-system codes as a permanent public API.

Conclusion

errno gives meaningful names to operating-system failure codes. It complements Python’s specific exception classes and remains valuable for native calls and non-blocking I/O.

Prefer specific exceptions, compare symbolic values instead of text, and design retries around both the error and operation semantics. Consult the official errno documentation and the official OSError documentation.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Side view of young cheerful ethnic female with book speaking on cellphone in public library while looking away
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python ctypes: Call C Libraries

    Learn Python ctypes to load C libraries, define types and pointers, manage memory, callbacks, ABI, and native errors safely.

    Ler mais

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

    Python expat: Low-Level XML Parsing

    Learn Python expat for low-level XML parsing, handlers, namespaces, diagnostics, and protections against amplification and denial of service.

    Ler mais

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

    Python ElementInclude: Safe XInclude

    Learn Python ElementInclude to use XInclude with safe loaders, base URLs, maximum depth, and blocked external paths.

    Ler mais

    Tempo de leitura: 4 minutos
    23/08/2026
    Close-up of a saxophone and sheet music stand, perfect for jazz lovers and musicians.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python xmlreader: Control SAX Parsers

    Learn Python xmlreader to configure SAX parsers, InputSource, incremental parsing, attributes, locators, and safer XML handling.

    Ler mais

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

    Python saxutils: XML Utility Functions

    Learn Python saxutils to escape XML, quote attributes, generate documents, build SAX filters, and avoid context mistakes.

    Ler mais

    Tempo de leitura: 5 minutos
    23/08/2026
    A close-up shot showcasing the intricate scales of a snake, highlighting texture and color.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python pulldom: Partial DOM for XML

    Learn Python pulldom to process XML events, expand only selected subtrees, and reduce memory use with safer limits.

    Ler mais

    Tempo de leitura: 5 minutos
    23/08/2026