I have a Python HTTP client built using the httpx library. The client worked fine when I was working with the test environment, but as soon as I pointed it to the prod environment, the request started failing with an HTTP 403 error. To be 100% sure, I tested the same request using the Bruno REST client and it worked. I used Bruno to generate cURL and Python 3 (without any dependencies) code, and they both worked as well. I spent 15 minutes debugging myself but couldn’t figure out the reason. The same request passing in Bruno, cURL, and Python 3 (without dependencies) was working, but the client code written with the httpx client library was failing.
So, I opened Claude Code and prompted it to debug the issue for me.
I am facing an issue where if I run the cURL request below it succeeeds. The same call if we make it to @app/clients/identity_client.py via id_test.py give 403. I am
having hard time understanding the difference between the two. Help me debug what is the difference between two and why it is failing. Then, help me fix it.
curl --request POST \
--url URL \
--header 'content-type: application/json' \
--data '{
"key": "00e78489023b4d6ea2ed440ef5fb3e2f",
"tenantDomain": "domain",
"username": "user"
}'
Claude Code first suggested that the 403 error was coming because of:
- Different base URLs: Your Python client uses env1.identitysystem.io but the working cURL uses env2.identitysystem.io
- Different key: The cURL uses a specific key while your client generates a random UUID
I told Claude that this was not the case. In my id_test.py I set the base URL to env2.identitysystem.io.
Claude Code then said:
You’re absolutely right! You are already setting the correct base URL in id_test.py. Looking at the client code again, the issue is likely the random key generation.
Claude Code then ran the Python client code with the key value from the cURL request and found out that the key is not the issue. Even with the same key, the API call was failing.
The issue persists. Let me debug further by checking if there are any HTTP headers differences. Let me modify the client to print the actual request being made and add proper headers:
Claude Code added debug logs to print headers and data to debug the issue.
Using the debug logs, it figured out the issue.
Great! Now I can see the issue more clearly. The response is an HTML 403 error from the load balancer (server: awselb/2.0), not from the API itself. This suggests there might be a User-Agent or other header requirement.
Now let’s test if setting a cURL-like User-Agent fixes the issue
Perfect! The issue was indeed the User-Agent header. The API/load balancer was blocking requests with the default httpx User-Agent but allows requests with a cURL-like User-Agent.
httpx library uses python-httpx/X.Y.Z as user agent where X.Y.Z depends on the httpx library version.
Claude Code successfully fixed the issue.
Root Cause: The Identity provider API/load balancer was blocking requests based on the User-Agent header. The default httpx User-Agent was being rejected with a 403 Forbidden error.
Conclusion
This type of issue is particularly frustrating for developers because environment dissimilarities create false assumptions. When the same request works in Bruno and cURL but fails in your application, you don’t immediately suspect something as basic as the User-Agent header.
These bugs are time-consuming because they violate our expectations – if the HTTP request is identical, it should work regardless of the client. The root cause often lies in subtle differences that aren’t obvious, like default headers that vary between tools.
Having a systematic debugging approach, whether through AI assistance or methodical logging, helps identify these hidden variables more efficiently than manual trial and error. Sometimes an external perspective is needed to spot what you’ve overlooked.


