PaddlePaddle/PaddleOCR · error · OSError

Failed to mkdir {}

Error message

Failed to mkdir {}

What it means

OSError from ppocr/utils/save_load.py mkdir_if_not_exists: os.makedirs(path) failed with an OSError that is NOT the benign EEXIST-race (another process just created the same directory). Typical causes are permission denied on a parent directory, a path component that is actually a file, a read-only filesystem, or an invalid path string.

Source

Thrown at ppocr/utils/save_load.py:63


FLAGS_json_format_model = get_FLAGS_json_format_model()


def _mkdir_if_not_exist(path, logger):
    """
    mkdir if not exists, ignore the exception when multiprocess mkdir together
    """
    if not os.path.exists(path):
        try:
            os.makedirs(path)
        except OSError as e:
            if e.errno == errno.EEXIST and os.path.isdir(path):
                logger.warning(
                    "be happy if some process has already created {}".format(path)
                )
            else:
                raise OSError("Failed to mkdir {}".format(path))


def load_model(config, model, optimizer=None, model_type="det", ema=None):
    """
    load model from checkpoint or pretrained_model
    """
    logger = get_logger()
    global_config = config["Global"]
    checkpoints = global_config.get("checkpoints")
    pretrained_model = global_config.get("pretrained_model")
    best_model_dict = {}
    is_float16 = False
    is_nlp_model = model_type == "kie" and config["Architecture"]["algorithm"] not in [
        "SDMGR"
    ]

    if is_nlp_model is True:
        # NOTE: for kie model dsitillation, resume training is not supported now

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Check permissions along the whole path and fix ownership (chown/chmod) or choose a writable output_dir in the config.
  2. Remove or rename any regular file that collides with a directory component of the path.
  3. On containerized runs, ensure the volume is mounted rw and the process user can write it.
  4. Re-run after fixing — the message names the exact failing path.

Example fix

# before
Global:
  save_model_dir: /opt/models/output  # not writable

# after
Global:
  save_model_dir: ./output
Defensive patterns

Strategy: validation

Validate before calling

import os

def ensure_writable_dir(path) -> None:
    parent = os.path.dirname(os.path.abspath(path)) or '.'
    assert os.path.isdir(parent), f'{parent} is not a directory'
    assert os.access(parent, os.W_OK), f'no write permission under {parent}'
    os.makedirs(path, exist_ok=True)

ensure_writable_dir(cfg['Global']['save_model_dir'])

Try / catch

try:
    os.makedirs(path, exist_ok=True)
except OSError as e:
    if e.errno == errno.EACCES:
        # pick a writable fallback root instead of failing the whole run
        path = os.path.join(tempfile.gettempdir(), os.path.basename(path))
        os.makedirs(path, exist_ok=True)
    else:
        raise

Prevention

When it happens

Trigger: Training/inference saving checkpoints, inference results, or visualization outputs to a directory that cannot be created: no write permission under the output root, a file occupying a path component (e.g. ./output exists as a file), or NFS/container read-only mounts.

Common situations: Running in Docker as non-root against a host-mounted volume; output_dir in config pointing into a protected path like /opt or /; leftover files named like the intended directory; multiprocess training where the race branch is handled but real permission errors are not.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/c70cb8c7b276fb01. Report an issue: GitHub.