encode/httpx · warning · RuntimeError
'.elapsed' may only be accessed after the response has been
Error message
'.elapsed' may only be accessed after the response has been read or closed.
What it means
RuntimeError raised by the Response.elapsed getter when _elapsed has not been set. httpx sets _elapsed inside the client's request machinery only after the response has been fully read or closed. Accessing response.elapsed on a Response you constructed yourself (Response(200, ...)) or before the request cycle completes therefore fails.
Source
Thrown at httpx/_models.py:585
self.stream = stream
self._num_bytes_downloaded = 0
def _prepare(self, default_headers: dict[str, str]) -> None:
for key, value in default_headers.items():
# Ignore Transfer-Encoding if the Content-Length has been set explicitly.
if key.lower() == "transfer-encoding" and "content-length" in self.headers:
continue
self.headers.setdefault(key, value)
@property
def elapsed(self) -> datetime.timedelta:
"""
Returns the time taken for the complete request/response
cycle to complete.
"""
if not hasattr(self, "_elapsed"):
raise RuntimeError(
"'.elapsed' may only be accessed after the response "
"has been read or closed."
)
return self._elapsed
@elapsed.setter
def elapsed(self, elapsed: datetime.timedelta) -> None:
self._elapsed = elapsed
@property
def request(self) -> Request:
"""
Returns the request instance associated to the current response.
"""
if self._request is None:
raise RuntimeError(
"The request instance has not been set on this response."
)View on GitHub (pinned to b5addb64f0)
Solutions
- Fully read or close the response first: `resp.read()` / `await resp.aread()` / `resp.close()`, then access resp.elapsed.
- For Responses you construct yourself (mocks/tests), set elapsed explicitly: resp.elapsed = datetime.timedelta(seconds=0.1).
- Guard access: `elapsed = getattr(resp, '_elapsed', None)`.
- When streaming, only read .elapsed after the iteration completes (after close() has run).
Example fix
// before resp = httpx.Response(200, content=b'hi') print(resp.elapsed) # RuntimeError // after resp = httpx.Response(200, content=b'hi') resp.elapsed = datetime.timedelta(seconds=0.05) print(resp.elapsed) # for real responses: resp = client.get(url) resp.read() # ensures elapsed is set print(resp.elapsed)
Defensive patterns
Strategy: validation
Validate before calling
# Ensure the response has been read/closed before timing access
if not hasattr(resp, '_elapsed'):
resp.read() # or resp.close(); for async use await resp.aread()
elapsed = resp.elapsed Type guard
import datetime
def response_elapsed_ready(resp: 'httpx.Response') -> bool:
return isinstance(getattr(resp, '_elapsed', None), datetime.timedelta) Try / catch
try:
elapsed = resp.elapsed
except RuntimeError:
elapsed = None # response not yet read/closed; or set a default Prevention
- Always read or close the response before accessing .elapsed.
- For Responses you construct (tests/mocks), set elapsed explicitly.
- Guard access with hasattr(resp, '_elapsed') or getattr.
- In streaming code, read .elapsed only after the iteration completes.
When it happens
Trigger: Accessing resp.elapsed on a Response constructed via httpx.Response(...) directly; accessing .elapsed inside a stream iteration before the body has been fully read/closed; accessing .elapsed on a response obtained from a mock/replay transport that does not set elapsed; reading .elapsed before aread()/close() in async code.
Common situations: Unit tests building Response objects manually; mock transports that omit elapsed; inspecting resp.elapsed inside an `async for chunk in resp.aiter_bytes()` loop (elapsed set only after the loop ends and close() runs); partial reads where the user did not consume the body.
Related errors
- The request instance has not been set on this response.
- Cannot call `raise_for_status` as the request instance has n
- The .request property has not been set.
- Attempted to access streaming request content, without havin
- Attempted to access streaming response content, without havi
AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04).
Data as JSON: /data/errors/d943e57a5f70c180.json.
Report an issue: GitHub.