fix: errorhandler no longer masks real exceptions (issue #25)#27
Merged
Conversation
The global @app.errorhandler(Exception) lazy-imported ProviderError from
inside the handler. If anything went wrong with that import — even on a
correctly bundled install — the resulting ModuleNotFoundError replaced
the original exception in server.log, leaving users with a misleading
"No module named 'ai_providers'" message instead of the root cause.
Three changes:
1. Hoist `from ai_providers import ProviderError` to top-level imports in
app.py. The package ships in the .app bundle — there's no reason it
was lazy. If a future build ever ships without it, the server now
fails loudly at startup with the import error visible in server.log,
instead of starting and 500-ing every request.
2. Make _handle_provider_error exception-proof. The ProviderError branch
is wrapped so that if jsonify or anything else inside ever raises,
we re-raise the ORIGINAL exception instead of substituting a new one.
3. Add tests/test_error_handler.py — three regression guards covering
the JSON-400 path, the re-raise path, and the top-level import.
Build / launcher hardening tied to the same failure mode:
- build_launcher.sh now verifies a denylist of critical paths exist in
the bundled APP_SRC after rsync (ai_providers/, doza_assist/, exporters/,
templates/, static/, app.py, etc.) and aborts the build if any are
missing. Also adds --exclude='.claude' so worktrees can't leak into the
DMG.
- launcher.sh's show_error_dialog now tails 50 lines instead of 15 and
prepends an actionable hint ("re-download the DMG") when server.log
contains ModuleNotFoundError.
Bumps version to 3.5.3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
doza-assist | 0432708 | May 20 2026, 02:15 PM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #25. The global
@app.errorhandler(Exception)lazy-importedProviderErrorfrom inside the handler — if that import ever raised, the resultingModuleNotFoundErrorreplaced the original exception inserver.log, masking the real root cause.from ai_providers import ProviderErrorto top-level imports. Fails loud at startup if the bundle is incomplete, instead of starting Flask and 500-ing every request with a misleading secondary error._handle_provider_errorexception-proof — re-raises the originaleif anything inside the handler ever throws.tests/test_error_handler.pywith three regression guards (JSON-400, re-raise, top-level import).build_launcher.sh: post-rsync existence check forai_providers/,doza_assist/,exporters/,templates/,static/,app.py, etc. — build aborts if any are missing. Also adds--exclude='.claude'to keep worktrees out of the DMG.launcher.sh: error dialog tails 50 lines instead of 15 and prepends a "re-download the DMG" hint whenserver.logcontainsModuleNotFoundError.Test plan
pytest tests/test_error_handler.pypasses (3/3)build_launcher.shsmoke-tests the bundled app cleanly with the hoisted import🤖 Generated with Claude Code