langchain-ai / langchain-ai/langgraph
Bug: default_retry_on retries non-retryable requests 4xx responses (Response.__bool__ truthiness)
- Dominant language
- Python
- Stars
- 41.9k
- Forks
- 7.1k
- Avg merge
- 23h 7m
- Merged PRs (30d)
- 30
Description
### Checked other resources
- [x] I searched the current issues and GitHub discussions to avoid duplicates.
### Description
`default_retry_on` in `langgraph/_internal/_retry.py` checks an HTTP error's response for truthiness before inspecting its status code:
```python
if isinstance(exc, requests.HTTPError):
return 500 <= exc.response.status_code < 600 if exc.response else True
```
`requests.Response.__bool__` is defined as `return self.ok`, i.e. `status_code < 400`. So a `Response` carrying any 4xx status is falsy and the whole expression falls back to `True` — every 4xx error raised through `requests` (400, 401, 403, 404, 422, ...) is classified as retryable. The `httpx` branch three lines above only retries 5xx, so the two HTTP stacks behave inconsistently and non-retryable client errors get retried up to the configured limit.
### Example
```python
import requests
from requests import HTTPError
from langgraph._internal._retry import default_retry_on
resp = requests.Response()
resp.status_code = 400
resp.request = requests.Request("GET", "https://example.com").prepare()
exc = HTTPError("400 Client Error", response=resp)
print(bool(resp)) # False — a 400 response is falsy
print(default_retry_on(exc)) # True — LangGraph will retry it
```
The second line should print `False`.
### Solution
Compare `exc.response is not None` instead of relying on truthiness, so a 4xx `HTTPError` falls through the same `500 <= status < 600` check used for `httpx`. I have a one-line fix plus a regression test ready and will open a PR referencing this issue.
Contributor guide
Research direction
Start in langgraph/_internal/_retry.py at default_retry_on and run the requests example from the issue to reproduce the incorrect classification. Add or inspect the mentioned regression test, then verify that 4xx requests errors are not retried while 5xx errors remain retryable and match the httpx branch.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100