From c281b6c5510064fdacbfb59ca780a88388b918eb Mon Sep 17 00:00:00 2001 From: Pier-Jean Malandrino Date: Tue, 7 Apr 2026 14:41:50 +0200 Subject: [PATCH] fix: classify pipeline errors into user-friendly messages (M1) Raw PyTorch/Docling stack traces are no longer shown to the user. Common failures (missing compiler, OOM, lock contention, corrupted document) are mapped to actionable messages. Unknown errors are truncated to 200 chars. Ref #57 (M1) --- document-parser/services/analysis_service.py | 28 +++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/document-parser/services/analysis_service.py b/document-parser/services/analysis_service.py index 4b62eaa..f630e95 100644 --- a/document-parser/services/analysis_service.py +++ b/document-parser/services/analysis_service.py @@ -191,7 +191,33 @@ class AnalysisService: except Exception as e: logger.exception("Analysis failed: %s", job_id) - await _mark_failed(job_id, str(e)) + await _mark_failed(job_id, _classify_error(e)) + + +def _classify_error(exc: Exception) -> str: + """Return a user-friendly error message based on the exception type/content.""" + msg = str(exc).lower() + + if "invalidcxxcompiler" in msg or "no working c++ compiler" in msg: + return "Missing C++ compiler — set TORCHDYNAMO_DISABLE=1 to work around this" + + if "out of memory" in msg or "oom" in msg: + return "Out of memory — try a smaller document or disable table structure analysis" + + if "could not acquire converter lock" in msg: + return "Server busy — a previous conversion is still running. Please retry later" + + if "pipeline" in msg and "failed" in msg: + return "Document processing failed — the document may be corrupted or unsupported" + + if "timeout" in msg: + return "Processing took too long — try with fewer pages or simpler options" + + # Fallback: truncate raw error to something reasonable + raw = str(exc) + if len(raw) > 200: + raw = raw[:200] + "…" + return raw _background_tasks: set[asyncio.Task] = set()