#1502·DeepTutor

[Bug]: Global parsing-engine selection hard-fails per file type — .txt/.md cannot coexist with MinerU-engine PDFs in one KB

Author: charlesliang-codeCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbug

Do you need to file an issue?

  • I have searched the existing issues and this bug is not already filed.
  • I believe this is a legitimate bug, not just a question or feature request.

Describe the bug

Document parsing applies a single global engine to every file in a KB (services/parsing/service.py::parse()). With the MinerU engine selected, uploading plain-text files fails hard, and the error message tells the user to switch the global engine — which would in turn break PDF/Office parsing for the same KB. A mixed-content KB (PDFs + .txt/.md notes or transcripts) is therefore impossible without splitting into separate KBs.

Root cause: MINERU_SUPPORTED_FORMATS deliberately mirrors the MinerU CLI's own format list (PDF + images + MINERU_OFFICE_FORMATS = {".docx", ".pptx", ".xlsx"}), so .txt/.md are rejected. Meanwhile DeepTutor already bundles several engines that handle text natively — text_only covers 100+ text suffixes at zero model cost, plus markitdown, tika, liteparse — but the global single-select never routes to them.

The failure aborts the whole ingest batch, taking otherwise-fine documents down with it:

ERROR deeptutor.knowledge.initializer #kb_init_... - Error processing documents:
LightRAG batch incomplete: added 4, failed 2, missing 0, nonterminal 0:
  9011-L1-1.txt: The 'mineru' parsing engine doesn't support .txt files. Choose a different engine in Settings → Document Parsing.;
  9011-L1-2.txt: The 'mineru' parsing engine doesn't support .txt files. Choose a different engine in Settings → Document Parsing.

With the parsing fleet expanding (liteparse #771, remote Tika #875, remote Docling #845, Office/image → MinerU routing #1098, PaddleOCR #1015), single-select + hard-fail will bite increasingly often: every engine has some unsupported type.

Steps to reproduce

  1. Settings → Document Parsing → select MinerU.
  2. Create a knowledge base; upload e.g. 4 PDFs + 2 .txt files.
  3. Initialize/index the KB.
  4. Result: added 4, failed 2 — the two text files fail with the message above; switching the global engine to text_only would instead fail the PDFs.

Expected Behavior

When the engine was chosen implicitly (the global default) and that engine does not support the file's suffix, fall back to an engine that does — e.g. preference order text_only > markitdown > tika — log the substitution, and continue. When the engine was explicitly pinned for the file, keep the current loud error (the user asked for that engine by name).

Notes that make the fallback safe:

  • Parsing signatures are engine-scoped (e.g. text_only/builtin-v1), so the content-addressed parse cache is unaffected — a file parsed via fallback doesn't collide with any MinerU-signature entry.
  • text_only requires no model and is lossless for text files, making it the natural first preference.

Suggested fix (reference implementation)

In services/parsing/service.py, add a helper and one branch in parse():

python
_FALLBACK_ENGINE_PREFERENCE = ("text_only", "markitdown", "tika")

def _find_fallback_engine(source_path: str | Path, primary: str):
    """First installed engine (other than `primary`) that supports this suffix."""
    for name in _FALLBACK_ENGINE_PREFERENCE:
        if name == primary:
            continue
        try:
            parser, config = get_parser_with_config(name)   # existing factory access
            supported = parser.supported_formats()
            if not supported or _matches_supported_format(source_path, supported):
                return name, parser, config
        except Exception:
            continue
    return None
python
# inside parse(), where the supported-format check currently raises:
if supported and not _matches_supported_format(source_path, supported):
    if engine is None:                     # implicit = global default → degrade
        fb = _find_fallback_engine(source_path, engine_name)
        if fb:
            logger.warning("engine %s doesn't support %s; using %s for this file",
                           engine_name, _display_extension(source_path, supported), fb[0])
            engine_name, parser, config = fb
            supported = parser.supported_formats()
        else:
            raise ...                       # unchanged error if nothing can take it
    else:
        raise ...                           # explicit engine: keep loud error

Applied locally: with MinerU selected globally, .txt files route to text_only automatically (PDFs untouched); explicit MinerU requests still raise the exact current error.

It would be even better if we could edit _FALLBACK_ENGINE_PREFERENCE in the settings.

Related Module

Knowledge Base Management

Configuration Used

Global parsing engine: MinerU (self-hosted CLI 3.4.5); mixed upload: PDF + .txt lecture transcripts in one KB.

Logs and screenshots

ERROR deeptutor.knowledge.initializer - Error processing documents: LightRAG batch incomplete: added 4, failed 2, missing 0, nonterminal 0: 9011-L1-1.txt: The 'mineru' parsing engine doesn't support .txt files. Choose a different engine in Settings → Document Parsing.; 9011-L1-2.txt: The 'mineru' parsing engine doesn't support .txt files. Choose a different engine in Settings → Document Parsing.
ERROR deeptutor.knowledge.progress_tracker - [kb_init_...] Failed to process documents - Error: LightRAG batch incomplete: added 4, failed 2, ...
ERROR deeptutor.api.routers.knowledge - [kb_init_...] Initialization failed: LightRAG batch incomplete: added 4, failed 2, ...

Additional Information

  • DeepTutor Version: v1.6.8 (PyPI)
  • Operating System: Windows 11
  • Python Version: 3.11
  • Related Issues: engine fleet PRs #771, #845, #875, #1098, #1015; retrieval UX context PR #492