docling-project/docling · error · RuntimeError

Archive member '{image_info.path}' is not a regular file (di

Error message

Archive member '{image_info.path}' is not a regular file (directory or symlink in tar).

What it means

RuntimeError raised while extracting a page image from a METS/GBS archive: tarfile.extractfile() returned None for the member referenced by the page's 'image' fileGrp entry. extractfile() returns None for non-regular members (directories, symlinks, devices), so the METS metadata points at something that is not a readable file — an integrity/security check against path traversal via tar links.

Source

Thrown at docling/backend/mets_gbs_backend.py:388

        # A page's fileGrp entries in the METS XML are independently optional (see
        # _PageFiles), so a page can legitimately have no `image` or `coordOCR` fptr
        # (e.g. a blank/cover page with no OCR layer). Report it as unparseable rather
        # than asserting, so the caller can mark it invalid and skip it, consistent
        # with how sibling PDF backends (e.g. DoclingParsePageBackend) handle a page
        # they can't build.
        image_info = self.page_map[page_no].image
        ocr_info = self.page_map[page_no].coordOCR
        if image_info is None or ocr_info is None:
            _log.warning(
                f"Page {page_no} is missing an 'image' or 'coordOCR' fileGrp entry; "
                "skipping."
            )
            return None, None

        # Security: limit extraction size to prevent decompression bombs
        image_file = self._tar.extractfile(image_info.path)
        if image_file is None:
            raise RuntimeError(
                f"Archive member '{image_info.path}' is not a regular file "
                "(directory or symlink in tar)."
            )
        image_file = cast(tarfile.ExFileObject, image_file)
        image_data = image_file.read(self.options.max_file_bytes + 1)
        if len(image_data) > self.options.max_file_bytes:
            raise ValueError(
                f"Image file {image_info.path} exceeds individual file size limit of {self.options.max_file_bytes} bytes"
            )

        # Security: Track total bytes extracted
        self._total_bytes_extracted += len(image_data)
        if self._total_bytes_extracted > self.options.max_total_bytes:
            raise ValueError(
                f"Total extracted data exceeds maximum limit of {self.options.max_total_bytes} bytes"
            )

        buf = BytesIO(image_data)

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Repack the archive materializing symlinks into real files: `tar -czhf` behaviors aside, use `tar -xzf` then `tar -czf` from the extracted tree.
  2. Verify each page's image entry with tarfile.getmember(path).isreg() before conversion.
  3. Regenerate the METS package from the source system so fileGrp references match actual members.
  4. Reject untrusted archives that fail this check — symlink members in a METS package are not legitimate.

Example fix

# before
result = converter.convert(mets_path)  # RuntimeError: not a regular file

# after (pre-check members are regular files)
import tarfile
with tarfile.open(mets_path) as t:
    bad = [m.name for m in t.getmembers() if not m.isfile() and not m.isdir()]
    assert not bad, f'archive contains non-regular members: {bad}'
result = converter.convert(mets_path)
Defensive patterns

Strategy: validation

Validate before calling

import tarfile

def image_members_are_regular(tar_path: str) -> bool:
    with tarfile.open(tar_path) as t:
        return all(m.isfile() for m in t.getmembers() if m.name.endswith(('.png', '.jpg', '.jpeg')))

Try / catch

try:
    result = converter.convert(mets_path)
except RuntimeError as e:
    if 'not a regular file' in str(e) and 'image' in str(e):
        log.error('METS image entry is a link/dir in %s — repack required', mets_path)

Prevention

When it happens

Trigger: Converting a METS archive where the fileGrp image entry resolves to a directory, a symlink, or a hard link instead of a regular file member; also when the referenced member name is absent from the archive in a form extractfile can open.

Common situations: Hand-assembled or repacked archives that converted regular files to symlinks (e.g. `tar -cf` with symlinked trees), METS files referencing entries by slightly different paths, or tampered archives attempting link-based tricks.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/ecbbde57e94c4883. Report an issue: GitHub.