fix: Django setup timing, auto app-ready, and urllib3 botocore support#81
Conversation
There was a problem hiding this comment.
1 issue found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="drift/instrumentation/django/instrumentation.py">
<violation number="1" location="drift/instrumentation/django/instrumentation.py:127">
P1: Restoring `django.setup` before calling it makes the deferred middleware hook racey on threaded startup.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Generated 25 tests - 25 passedTip New to Tusk Unit Tests? Learn more here. Test Summary
ResultsTusk's tests are all passing and cover three critical fixes in this PR. The Django middleware auto-ready tests validate that View check history
Was Tusk helpful? Give feedback by reacting with 👍 or 👎 |
There was a problem hiding this comment.
1 issue found across 6 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="drift/instrumentation/urllib3/instrumentation.py">
<violation number="1" location="drift/instrumentation/urllib3/instrumentation.py:933">
P1: Missing `_normalize_headers()` in `_try_get_mock` — replay mode will crash with `TypeError` when botocore passes bytes headers. The same bytes-header fix applied to `_finalize_span` needs to be applied here.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
…se recording + filter non tcp logs
There was a problem hiding this comment.
1 issue found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="drift/instrumentation/urllib3/instrumentation.py">
<violation number="1" location="drift/instrumentation/urllib3/instrumentation.py:908">
P1: Only remove `content-encoding` after successful decompression. Right now failed/unsupported decompression still strips the header, which can corrupt replayed responses.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="drift/instrumentation/urllib3/instrumentation.py">
<violation number="1" location="drift/instrumentation/urllib3/instrumentation.py:1009">
P1: `Content-Encoding` lookup is case-sensitive, so compressed responses may not be decompressed before recording/replay.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.



Summary
Fixes to improve Django onboarding reliability, reduce manual setup, and resolve urllib3 instrumentation failures with botocore/boto3.
1. Django middleware injection timing fix
When
TuskDrift.initialize()is called at the top of a Djangomanage.py(as our setup instructions recommend), Django settings are not yet configured —DJANGO_SETTINGS_MODULEhasn't been set anddjango.setup()hasn't run. The middleware injection silently failed, meaningDriftMiddlewarewas never added to the middleware stack. Without it, no SERVER spans (kind 2) were created — only CLIENT spans (kind 3) from outbound instrumentations (requests, psycopg2, redis). Sincetusk drift listfilters for SERVER spans to identify traces, it reported "No traces found" even though the app was running and handling requests normally.The root cause is a timing issue:
DjangoInstrumentation.patch()checkssettings.configured→False→ gives up__drift_patched__, so the patch is never retriedDriftMiddlewarein the stackThe fix defers middleware injection to
django.setup()when settings aren't available at patch time.2. Auto-mark app as ready on first inbound request
Previously, apps had to explicitly call
TuskDrift.get_instance().mark_app_as_ready()(e.g. in Django'sAppConfig.ready()). If this was missed, all spans were recorded withisPreAppStart: trueand the SDK never transitioned to normal recording mode.Now, all three framework handlers (Django middleware, FastAPI, WSGI/Flask) automatically call
mark_app_as_ready()on the first inbound HTTP request if the app hasn't been marked ready yet. This acts as a safety net — explicitmark_app_as_ready()calls still work and take precedence (unless they are called after first inbound request).3. Skip non-HTTP schemes in urllib instrumentation
The urllib instrumentation was intercepting all
urlopen()calls, includingfile://URLs. Libraries likexmlschemauseurlopen("file:///path/to/schema.xsd")to read local files. In REPLAY mode, the SDK tried to find a mock for these local file reads and crashed withRuntimeError: No mock foundlikely bc these spans were filtered out due to size.The fix checks the URL scheme early and passes through anything that isn't
http://orhttps://. This is safe becausefile://,data://,ftp://, etc. are local operations.4. Fix urllib3 instrumentation for botocore/boto3 (
preload_content=False)botocore uses
preload_content=Falsefor all HTTP requests via urllib3, which means the response body isn't read during construction — callers useresponse.read()later. This caused three cascading failures:Bytes header handling: botocore/urllib3 can produce headers with
byteskeys/values instead ofstr. This causedTypeError: a bytes-like object is required, not 'str'in_get_decoded_type_from_content_type()and would break JSON serialization of headers. Fixed by adding_normalize_headers()and decoding bytes in content-type helpers.Response body not captured during recording: The old code skipped body capture entirely for
preload_content=Falseresponses to "avoid breaking the application." This meant replay had no body to return, causing 500 errors. Fixed by reading the raw bytes fromresponse._fpand replacing_fpwith aBytesIOso the caller's subsequentread()still works. A 1 MB size guard prevents buffering very large streaming downloads.Mock response broken during replay:
_create_mock_response()usedpreload_content=True, which exhausted theBytesIOduring construction. urllib3'sread()does not check_body— only the.dataproperty does. So botocore'sresponse.read()gotb"", CRC32 checksum was 0, andChecksumErrorwas raised. Fixed by usingpreload_content=Falsefor mock responses, leaving theBytesIOunread in_fpfor the caller.Also added
exc_info=Trueto the catch-all error logger in_finalize_spanfor better debugging.E2e tests added for the
preload_content=Falsepattern:read()(botocore pattern),read()+ CRC32 validation (DynamoDB pattern), andstream()(chunked reading). Previously these were excluded from the replay test suite.