Fix 13 production error patterns across 15 files with 27 tests#3257
Draft
cursor[bot] wants to merge 4 commits intomainfrom
Draft
Fix 13 production error patterns across 15 files with 27 tests#3257cursor[bot] wants to merge 4 commits intomainfrom
cursor[bot] wants to merge 4 commits intomainfrom
Conversation
- utils/sentry.py: log_error base_error scope now records str(base_error) instead of the message parameter (was always overwritten) - utils/sentry.py: log_request_error wraps string messages in Exception before passing to capture_exception (Sentry API requires Exception) - utils/message.py: Fix list mutation during iteration in recipient filtering that could skip valid recipients - Add 6 tests covering both fixes
- unified_search_service.py: Guard against empty highlight fragment lists before indexing (prevents IndexError in _extract_document_highlights) - person.py serializer: Handle None/malformed institutions from OpenSearch with safe .get() access and None filtering - suggest.py: Return early when indexes list is empty to prevent ZeroDivisionError in perform_regular_search - Add 12 tests covering all three fixes
- paper_views.py: Use .get() for paper_ids query param (prevents KeyError)
and wrap Paper.objects.get in try/except (fixes dead 'if not paper' guard)
- paper_upload_tasks.py: Guard against empty title list from Crossref API
(prevents IndexError on results.get('title', [])[0])
- openalex_util.py: Check work_id is not None before calling .split()
- biorxiv_base.py: Use (value or default) pattern to handle None server
field before calling .lower()
- Add 8 tests covering the patterns
- purchase/tasks.py: Fix NameError when url is unset for 'profile' content_type; guard uploaded_by None; guard paper_type None; wrap Paper/Post lookups in try/except DoesNotExist - note/views/note_view.py: Harden CKEditor webhook against KeyError, TypeError, and Note.DoesNotExist; fix int() ValueError on expire param - review/views/review_view.py: Wrap objects.get calls with DoesNotExist handling; add ContentType.DoesNotExist guard - research_ai views: Catch ValueError/TypeError on int() query param parsing in expert_finder, template, and email list views
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3257 +/- ##
==========================================
- Coverage 79.09% 79.08% -0.01%
==========================================
Files 620 620
Lines 35081 35130 +49
==========================================
+ Hits 27746 27784 +38
- Misses 7335 7346 +11 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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
Systematic code-driven investigation of the codebase to identify and fix error-prone patterns that cause production exceptions. This PR addresses 13 distinct error patterns across 15 source files, with 27 new tests.
Error Signatures Addressed
1. Sentry SDK Misuse (
utils/sentry.py)log_errorbase_error scope bug:scope.set_extra("base_error", message)was recording the message string instead of the base_error — lost the original exception context in Sentry.log_request_errorpassing string tocapture_exception: Sentry'scapture_exception()expects an Exception, but received a plain string — resulted in malformed Sentry events or silent failures.2. List Mutation During Iteration (
utils/message.py)recipients.remove(recipient)insidefor recipient in recipients— caused valid recipients to be skipped when consecutive invalid emails appeared.3. IndexError on Empty Highlights (
search/services/unified_search_service.py)highlights.paper_title[0]without checking if the fragment list is empty — OpenSearch can return empty fragment lists, causing IndexError.4. KeyError on Malformed Institutions (
search/serializers/person.py)institution["id"]andinstitution["name"]on OpenSearch AttrList data — None entries or missing keys caused KeyError during API serialization.5. ZeroDivisionError (
search/views/suggest.py)math.ceil(limit / len(indexes))whenindexesis empty — caused ZeroDivisionError.6. ValueError on Query Params (
research_ai/views/,note/views/note_view.py)int(request.query_params.get("limit", 10))without try/except — non-numeric values likelimit=abccaused unhandled ValueError → 500.ExpertSearchListView,EmailTemplateListView,GeneratedEmailListView, and Noteinvite_user.7. KeyError on Missing
paper_ids(paper/views/paper_views.py)request.query_params["paper_ids"]— missing query param caused KeyError → 500.8. Dead None Guard (
paper/views/paper_views.py)paper = Paper.objects.get(id=paper_id)followed byif not paper:—objects.getnever returns falsy; it raises DoesNotExist. The guard was unreachable.9. None.split() on Missing Work ID (
paper/openalex_util.py)work.get("id").split("/")— when"id"key is present butNone, calling.split()onNoneraised AttributeError.10. None.lower() on Server Field (
paper/ingestion/mappers/preprints/biorxiv_base.py)record.get("server", default).lower()— when key exists with explicitNonevalue, default is not used, causing AttributeError on.lower().11. IndexError on Empty Crossref Title (
paper/paper_upload_tasks.py)results.get("title", [])[0]— empty title list from Crossref API caused IndexError.12. Multiple Crash Paths in
send_support_email(purchase/tasks.py)urlreferenced in context dict but never defined whencontent_typeis "profile".paper.uploaded_by.full_name()whenuploaded_byis None.paper.paper_type.split("_")whenpaper_typeis None.Paper.objects.get()/ResearchhubPost.objects.get()calls.13. Unguarded objects.get in Review Create (
review/views/review_view.py)ResearchhubUnifiedDocument.objects.get(id=args[0])andContentType.objects.get(model=...)— both could raise DoesNotExist → 500.Validation
Remaining Risk