Repository navigation
fix: remove the last broad exception handlers, cover remaining invariants - #14
Closed
Blackwellcode wants to merge 7 commits into
Closed
Blackwellcode wants to merge 7 commits into
Blackwellcode wants to merge 7 commits into
Conversation
Fifteen `try: response.close() except Exception: pass` blocks in the storage HTTP layer and the Google Drive, Dropbox, OneDrive, WebDAV and S3 providers become http.close_quietly(). It catches only OSError (socket already gone, requests' ConnectionError) and urllib3's HTTPError, logs them at debug level with the provider name, and lets anything else propagate. The transfer result is unchanged: closing only returns the connection to the pool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- base: a failing config-changed callback (rotated OAuth token not persisted) is caught as StorageError/sqlite3.Error/OSError/ValueError and logged as a warning; the request still succeeds as before. - service: a locked database while saving transfer progress is logged at debug level; a failure to record the provider error after a failed restore is logged as a warning and the restore error is still raised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ss helpers Ten `except Exception: pass` handlers outside storage and the web UI now catch the specific failure and leave a log line; every fallback value is unchanged: - twitch_api/twitch_eventsub: an unreadable HTTP error body (OSError, http.client.HTTPException) is logged at debug level; the status code still decides the result. reload_env() calls redis_client.delete_state() directly because it already absorbs Redis errors. - live_watch_diag: sqlite3.Error/ValueError reading channel configs is a warning; the diagnosis continues without the database fields. - chat_chunker: an unreadable cached meta.json is a warning and the chunks are rebuilt. - redis_client: failing to remove the dashboard shm cache is a warning. - tube_auth: sqlite3.Error reading VOD access rows is a warning and the seed list is used, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
abort_deleted_media() called abort(404) inside `try ... except Exception: pass`. werkzeug's NotFound is an Exception, so the handler swallowed it and a tombstoned VOD or clip whose file was still on disk (restore, failed unlink, re-sync) kept opening in the player. The tombstone lookup now catches only sqlite3.Error, logs it and serves as before; abort(404) runs outside the handler. The alias lookup in the same function logs sqlite3.Error instead of passing silently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The last sixteen pass-only broad handlers in webui.py (plus the adjacent channel-config lookup in twitch_watch) catch the failure they guard against and log a warning; every fallback stays as it was: - channel/alias lookups (can_view_streamer, resolve_media_path, delete_video_file, list_all_streamer_folders, _recording_logins_set, twitch_watch, _vod_access_candidate_slugs): sqlite3.Error, plus OSError where the archive folder or recording state is read. - Twitch GQL profile/user-id lookups: OSError (URLError, timeouts), ValueError (bad JSON) and http.client.HTTPException. Unexpected answer shapes are parsed by _twitch_gql_user() instead of raising AttributeError into the handler. - maintenance bypass check: OSError/ValueError, user stays not exempt. - title from the chat log in read_media_sidecar_metadata: OSError. - can_view_streamer no longer wraps normalize_channel_name(), which is pure string work and cannot fail. AST count of `except Exception/bare: pass` outside tests: 46 -> 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…top and worker paths Closes the remaining gaps from the test audit (06-tests 1.3 a/c/d): - ChannelLockFileTests: the lock file carries the child PID after spawn; release_channel_lock() leaves a held or foreign lock alone unless the PID matches. - InstanceLockRealFlockTests (POSIX): a second recorder instance exits with status 1 while another process holds the instance flock. - StopChannelProcessRealChildTests (POSIX, fork): a channel worker that ignores SIGTERM is SIGKILLed within the deadline. - WorkerVodTaskPathTests: _safe_vod_task_path() rejects traversal, absolute names, temp/non-archive files and symlinks out of the archive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 12, 2026
Merged
Owner
Author
Blackwellcode
added a commit
that referenced
this pull request
Nov 12, 2026
fix: log every silently swallowed error, catch expected classes only (supersedes #14)
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
Removes the last 46
except Exception/bare: passhandlers (audit finding B5) and adds tests for the invariant functions that still had none (audit finding T1).Every fallback value stays the same. Only the listed error classes are absorbed; anything else now propagates.
Evidence
pass: 46.unittest discover -s tests:Ran 328 tests ... OK (skipped=20). A tombstoned VOD with its file still on disk:GET /vod/streamer/vod.mp4-> 200.After (this branch): AST count 0.
Ran 361 tests ... OK (skipped=23)(Windows; the POSIX tests run in CI). Same request -> 404 (DeletedMediaTombstoneTests.test_tombstoned_vod_page_is_404, red before the fix, green after).sqlite3.OperationalError("database is locked"),ConnectionResetError,URLError,PermissionError, corruptmeta.json). Each checks that the fallback still comes back and that a log line is written:tests/test_error_handling.py(22 tests), plusStorageBookkeepingFailureTestsintests/test_storage.py. The three without a dedicated test: the chat-log title read inread_media_sidecar_metadata, the config lookups intwitch_watch, andtwitch_eventsub.reload_env(thedelete_statecall there absorbs Redis errors itself).tests/test_invariants.py: lock-file PID ownership, the instance flock across processes (POSIX), SIGKILL fallback for a channel worker that ignores SIGTERM (POSIX), and traversal and symlink rejection inworker._safe_vod_task_path(17/17 lines covered, was 1/17).ruff check .: All checks passed.compileall: OK.Merge Danger
Door: two-way
Plain revert. No schema, config or data changes.
Blast Radius: narrow
Narrowing
except Exceptionmeans an unexpected error class (for example aTypeErrorfrom a malformed row) now shows up as an HTTP 500 or a traceback in the log, where it used to vanish. That is intended. Deleted VODs and clips whose file still exists now return 404, which was always the intended behaviour.🤖 Generated with Claude Code