docling-project/docling · error · RuntimeError

Expected an OpenDocument {self._odf_type!r} but got {self.od

Error message

Expected an OpenDocument {self._odf_type!r} but got {self.odf_obj.get_type()!r}

What it means

RuntimeError raised in _OdfBaseBackend.__init__ after successfully loading an ODF package whose odfdo get_type() does not match the subclass's _odf_type ('text' for ODT, 'presentation' for ODP, 'spreadsheet' for ODS). It prevents, e.g., the ODT backend from walking a spreadsheet body.

Source

Thrown at docling/backend/opendocument_backend.py:169

    _odf_type: str = ""  # "text", "spreadsheet" or "presentation"

    @override
    def __init__(
        self,
        in_doc: InputDocument,
        path_or_stream: BytesIO | Path,
        options: OdsBackendOptions | None = None,
    ) -> None:
        if not _ODFDO_AVAILABLE:
            raise ImportError(_INSTALL_HINT) from _ODFDO_IMPORT_ERROR
        super().__init__(in_doc, path_or_stream, options)
        self.path_or_stream: BytesIO | Path = path_or_stream
        self.valid: bool = False
        self.odf_obj: OdfDocument = _load_odf_document(
            path_or_stream, self.document_hash
        )
        if self._odf_type and self.odf_obj.get_type() != self._odf_type:
            raise RuntimeError(
                f"Expected an OpenDocument {self._odf_type!r} but got "
                f"{self.odf_obj.get_type()!r}"
            )
        self.valid = True

    @override
    def is_valid(self) -> bool:
        return self.valid

    @override
    def unload(self):
        if isinstance(self.path_or_stream, BytesIO):
            self.path_or_stream.close()
        self.path_or_stream = None


def _find_true_data_bounds(table: OdfTable) -> tuple[int, int, int, int]:
    """Find the true data boundaries (min/max rows and columns) in an ODS table.

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Detect the true type with odfdo or by reading the ODF mimetype entry and dispatch to the matching backend.
  2. Fix the file extension to match the actual document type and retry.
  3. Re-save the document from its native application with the correct type.
  4. In custom pipelines, key InputFormat off python-magic/filetype detection rather than the filename suffix.

Example fix

# before
conv = DocumentConverter(format=[InputFormat.ODT])
res = conv.convert('actually_a_sheet.odt')  # RuntimeError: expected 'text' got 'spreadsheet'

# after
import filetype  # or read the ODF 'mimetype' entry
kind = filetype.guess_mime(path)
fmt = {'application/vnd.oasis.opendocument.spreadsheet': InputFormat.ODS,
       'application/vnd.oasis.opendocument.text': InputFormat.ODT,
       'application/vnd.oasis.opendocument.presentation': InputFormat.ODP}[kind]
res = DocumentConverter(format=[fmt]).convert(path)
Defensive patterns

Strategy: validation

Validate before calling

import zipfile
with zipfile.ZipFile(path) as z:
    odf_type = z.read('mimetype').decode()
# map mimetype -> InputFormat and dispatch accordingly

Try / catch

try:
    backend = OdsBackendClass(in_doc, path)
except RuntimeError as e:
    if 'Expected an OpenDocument' in str(e):
        retry_with_correct_backend(detect_odf_type(path))

Prevention

When it happens

Trigger: A .ods file renamed to .odt (or any ODF type/format mismatch) is dispatched to the wrong backend by extension-based format detection; the mimetype inside content.xml disagrees with the backend's expectation.

Common situations: User-uploaded files with wrong extensions, pipelines that guess InputFormat from the suffix instead of MIME sniffing, mixed ODF exports misnamed during bulk conversion.

Related errors


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