run-llama/liteparse · error · ParseError

{data}

Error message

{data}

What it means

Raised when the worker completed the request but reported a non-ok status: the message is the verbatim '{ExceptionType}: {detail}' string produced inside the worker when native parsing raised. This is the normal channel for in-process parse failures (corrupt PDFs, unsupported files, native errors) when using the pool — the actual exception type is flattened into a string inside ParseError.

Solutions

  1. Read the leading type name in the message (e.g. 'FileNotFoundError: ...') — it is the native exception flattened to a string
  2. If it is a missing converter, install the external tool (e.g. LibreOffice) on the machine running the workers
  3. If it is a corrupt/encrypted PDF, validate or decrypt the document before parsing
  4. Confirm the file path is absolute and readable from the worker process (the worker parses the path independently)
  5. If the message hides too much detail, run once without pool_size to get the full native traceback

Example fix

# before
parser = LiteParse(pool_size=2)
result = parser.parse("doc.docx")  # ParseError: IOException: soffice not found

# after
# install the converter first, e.g.: apt-get install -y libreoffice
import shutil
assert shutil.which("soffice"), "LibreOffice required for office formats"
result = LiteParse(pool_size=2).parse("doc.docx")
Defensive patterns

Strategy: try-catch

Validate before calling

from pathlib import Path
def assert_parsable_input(file_data) -> None:
    if isinstance(file_data, str):
        p = Path(file_data)
        if not p.is_file():
            raise FileNotFoundError(p)
        if p.suffix.lower() in {".docx", ".xlsx", ".pptx"} and not shutil.which("soffice"):
            raise RuntimeError("LibreOffice (soffice) required for office formats")

Try / catch

from liteparse.types import ParseError
try:
    result = parser.parse(path)
except ParseError as e:
    # message is 'ExceptionType: detail' from the worker
    kind, _, detail = str(e).partition(": ")
    log.error("parse failed (%s): %s", kind, detail)
    raise

Prevention

When it happens

Trigger: Any parse() / parse_bytes() call on a pooled LiteParse where native.parse() or native.parse_bytes() raises inside the worker: malformed/encrypted PDF, file path unreadable by the worker, unsupported format, conversion tool (LibreOffice) missing, etc.

Common situations: Passing an encrypted or corrupt PDF; pointing at a path that exists for the parent but not in the worker's context; DOCX/XLSX conversion failing because LibreOffice is not installed; anything that would throw the underlying native exception without a pool.

Related errors


AI-assisted analysis of run-llama/liteparse@22d2dd8cd7 (2026-09-08). Data as JSON: /api/errors/1dba2983ac950b05. Report an issue: GitHub.

Appendix: source

Thrown at packages/python/liteparse/_pool.py:270

            replace = True
            raise ParseError(
                f"liteparse worker process died while parsing {source}: {e}"
            ) from None
        except _WorkerInitFailed as e:
            replace = True
            raise ParseError(f"liteparse worker failed to initialize: {e}") from None
        finally:
            if replace:
                self._retire_worker(worker)
                if not self._closed:
                    self._spawn_worker()
            elif self._closed:
                worker.stop()
            else:
                self._idle.put(worker)
        if status == "ok":
            return data
        raise ParseError(data)

    def warm_up(self) -> None:
        """Block until every worker has finished initializing.

        Optional — the first parse per worker waits for init anyway. Useful
        before latency-sensitive traffic or benchmarks.
        """
        workers = list(self._workers)
        for worker in workers:
            worker._ensure_ready()

    def close(self) -> None:
        """Shut down all workers. Idempotent."""
        if self._closed:
            return
        self._closed = True
        # Stop the workers we can grab; busy workers are stopped by parse()'s
        # finally-block when they come back (see the _closed check there).

View on GitHub (pinned to 22d2dd8cd7)