Skip to content

Propagate errors instead of swallowing them across pipeline and scripts - #3

Open
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1785356627-improve-error-handling
Open

Propagate errors instead of swallowing them across pipeline and scripts#3
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1785356627-improve-error-handling

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 29, 2026

Copy link
Copy Markdown

Summary

Audit of error handling in src/ and scripts/. Failures were being hidden in three ways: swallowed exceptions (except: pass, fallbacks to empty values), errors logged but never surfaced to the caller/exit code, and API responses whose failures were treated as "no prediction". Every script now returns a non-zero exit code when inputs are missing or any item fails, and library code raises typed exceptions.

Highlights:

src/openrouter_classifier.py — a malformed/error API response used to become an empty prediction that scored as a wrong answer:

-    try:
-        prediction = result["choices"][0]["message"].get("content") or ""
-    except (KeyError, IndexError, AttributeError):
-        prediction = ""          # silently becomes an "empty_response" result
+    if isinstance(result.get("error"), dict):        # OpenRouter reports upstream failures in 200 bodies
+        raise OpenRouterError(...)
+    try:
+        prediction = result["choices"][0]["message"].get("content") or ""
+    except (KeyError, IndexError, TypeError, AttributeError) as e:
+        raise OpenRouterError(f"Unexpected OpenRouter response shape ...") from e

New OpenRouterError also covers connection failures, non-JSON bodies, HTTP errors (previously print + reraise of a bare HTTPError with no context), and unreadable image files. clean_prediction now warns when the model output contains no valid class name instead of silently returning arbitrary text.

src/document_processor.py — the Tesseract configuration was wrapped in try: ... except Exception: pass, which never actually caught anything (attribute assignment can't fail) and left a Windows-only path configured on other platforms:

-try:
-    pytesseract.pytesseract.tesseract_cmd = TESSERACT_PATH
-except Exception:
-    pass  # Tesseract may already be in PATH
+if Path(TESSERACT_PATH).is_file():
+    pytesseract.pytesseract.tesseract_cmd = TESSERACT_PATH
+elif shutil.which(pytesseract.pytesseract.tesseract_cmd) is None:
+    logger.warning("Tesseract not found ... OCR calls will fail until it is installed")

Also: new DocumentProcessingError for unreadable images, OCR failures (TesseractNotFoundError / TesseractError now get an actionable message instead of a raw pytesseract error), and failed image/JSON writes; logger.error(e)logger.exception so tracebacks are kept; batch results carry error_type; _optimize_image guards against zero/non-numeric DPI metadata (previously ZeroDivisionError); the __main__ block returns an exit code instead of printing Error: ... and exiting 0.

src/env_utils.py — split the shared helper so library code can propagate instead of exiting mid-call, and the optional-dotenv except ImportError: pass now says why env vars may be missing:

def get_env(*names) -> tuple[str, ...]:   # raises MissingEnvironmentError
def require_env(*names):                  # get_env + print + sys.exit(1), for entrypoints only

scripts/run_tiff_processing.py, create_balanced_dataset.py, eda_analysis.py, eda_dimensions_summary.py, create_fixed_size_dataset.py, braintrust_metrics_visual.py, braintrust_openrouter_input.py, estimate_openrouter_cost.py, download_dataset.py all validate inputs up front and sys.exit(main()). Notable per-file fixes:

  • eda_dimensions_summary.py: unreadable images were counted into skipped with no reason recorded — errors are now printed and listed in the summary JSON.
  • eda_analysis.py: an empty dataset previously produced AttributeError/KeyError deep in analysis; now raises a clear error, and unreadable files are reported in the JSON report.
  • create_balanced_dataset.py: a single failing shutil.copy2 aborted the run mid-way; failures are per-file, logged, and MISMATCH/MISSING verification results now fail the run.
  • braintrust_metrics_visual.py: sys.exit() inside the fetch helper replaced by BraintrustFetchError; retry loop no longer relies on a possibly stale resp and now retries all RequestExceptions (not just Timeout); an experiment with zero usable rows errors out instead of rendering an empty chart; the dead if metrics.get("tokens"): pass branch now populates reasoning_tokens_avg (it was always reported as 0), and the hardcoded | Errors | 0 | row in the generated experiment log reports the real error count.
  • braintrust_openrouter_input.py: a missing/misnamed dataset dir silently ran an eval over 0 images; now raises, and skipped unlabeled filenames are reported.

Verified by unit-poking the new failure paths (fake non-JSON / error-body / empty-choices responses, missing image files, missing Tesseract, missing input dirs, missing env vars) and confirming the scripts exit 1. Ruff: blind-except 11 → 1 (the remaining one intentionally wraps kagglehub), try-except-pass and unused-variable gone; remaining findings are pre-existing style issues. Merged main (#2's shared src/ utilities) into the branch — the error handling is reconciled with find_images / encode_image_base64 / print_header / require_env.

Link to Devin session: https://app.devin.ai/sessions/a40dcf36c84c4e6bb637d7826d6fcb2c
Requested by: @Exios66

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@Exios66 Exios66 self-assigned this Jul 29, 2026
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Exios66 and others added 2 commits July 29, 2026 20:29
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…val script

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant