The Fix
Upgrade to version 0.18.0 or later.
Based on closed encode/httpx issue #1404 · PR/commit linked
@@ -37,6 +37,26 @@ HTTPX uses `utf-8` for encoding `str` request bodies. For example, when using `c
For response bodies, assuming the server didn't send an explicit encoding then HTTPX will do its best to figure out an appropriate encoding. Unlike Requests which uses the `chardet` library, HTTPX relies on a plainer fallback strategy (basically attempting UTF-8, or using Windows-1252 as a fallback). This strategy should be robust enough to handle the vast majority of use cases.
+## Cookies
+
+If using a client instance, then cookies should always be set on the client rather than on a per-request basis.
import flask
app = flask.Flask(__name__)
@app.route('/r')
def r():
return "yes" if "test" in flask.request.cookies else "no"
@app.route('/same_domain_redirect')
def same_domain_redirect():
return flask.redirect("/r", code=302)
@app.route('/cross_domain_redirect')
def cross_domain_redirect():
return flask.redirect("http://localhost:5000/r", code=302)
@app.route('/same_domain_redirect_expire')
def same_domain_redirect_expire():
resp = flask.redirect("/r", code=302)
resp.set_cookie('test', '', expires=0)
return resp
if __name__ == '__main__':
app.run()
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Upgrade to fixed release\nUpgrade to version 0.18.0 or later.\nWhen NOT to use: This fix is not suitable if per-request cookie handling is required for specific use cases.\n\n
Why This Fix Works in Production
- Trigger: DIRECT_URL="" # your webhook.site URL
- Mechanism: Cookies were not being persisted across redirects due to per-request cookie handling
- Why the fix works: Deprecates the use of per-request cookies in favor of setting cookies on the client instance to ensure clearer expectations around cookie persistence, especially during redirects. (first fixed release: 0.18.0).
- If left unfixed, this can cause silent data inconsistencies that propagate (bad cache entries, incorrect downstream decisions).
Why This Breaks in Prod
- Cookies were not being persisted across redirects due to per-request cookie handling
- Production symptom (often without a traceback): DIRECT_URL="" # your webhook.site URL
Proof / Evidence
- GitHub issue: #1404
- Fix PR: https://github.com/encode/httpx/pull/1574
- First fixed release: 0.18.0
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.85
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.52
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“I'm going to *tentatively* milestone this for 0.17, which I assume will be released next week. I don't think we *necessarily* need to act on…”
“@tomchristie Wouldn't the path of least resistance be to do what requests do, since the API looks so similar that any behavioral divergence from this…”
“@JanPokorny No I think that's just an internal implementation note, the behavior stays the same: httpx.get(...) doesn't maintain cookies across calls. The throwaway client used…”
“In my tests, this can be worked around by passing the cookies to the client object itself (instead of the individual get calls).”
Failure Signature (Search String)
- DIRECT_URL="" # your webhook.site URL
- It's a bit awkward to explain why, but if we break it down to the two sub-calls...
Copy-friendly signature
Failure Signature
-----------------
DIRECT_URL="" # your webhook.site URL
It's a bit awkward to explain why, but if we break it down to the two sub-calls...
Error Message
Signature-only (no traceback captured)
Error Message
-------------
DIRECT_URL="" # your webhook.site URL
It's a bit awkward to explain why, but if we break it down to the two sub-calls...
Minimal Reproduction
import flask
app = flask.Flask(__name__)
@app.route('/r')
def r():
return "yes" if "test" in flask.request.cookies else "no"
@app.route('/same_domain_redirect')
def same_domain_redirect():
return flask.redirect("/r", code=302)
@app.route('/cross_domain_redirect')
def cross_domain_redirect():
return flask.redirect("http://localhost:5000/r", code=302)
@app.route('/same_domain_redirect_expire')
def same_domain_redirect_expire():
resp = flask.redirect("/r", code=302)
resp.set_cookie('test', '', expires=0)
return resp
if __name__ == '__main__':
app.run()
What Broke
Requests after redirects did not include expected cookies, leading to inconsistent behavior.
Why It Broke
Cookies were not being persisted across redirects due to per-request cookie handling
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.18.0 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Fix reference: https://github.com/encode/httpx/pull/1574
First fixed release: 0.18.0
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix is not suitable if per-request cookie handling is required for specific use cases.
Verify Fix
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Did This Fix Work in Your Case?
Quick signal helps us prioritize which fixes to verify and improve.
Prevention
- Add a CI check that diffs key outputs after upgrades (OpenAPI schema snapshots, JSON payload shapes, CLI output).
- Upgrade behind a canary and run integration tests against the canary before 100% rollout.
- Add a TLS smoke test that performs a real handshake in CI (include CA bundle validation and hostname checks).
- Alert on handshake failures by error string and endpoint to catch cert/CA changes quickly.
Version Compatibility Table
| Version | Status |
|---|---|
| 0.18.0 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.