D4Vinci/Scrapling · error · RuntimeError
No active session available.
Error message
No active session available.
What it means
Raised inside _SyncSessionLogic.fetch when no curl session is available to send the request with. The method first tries self._curl_session (set by __enter__), then falls back to creating a one-off CurlSession, but only when _curl_session is the _NO_SESSION sentinel and __enter__ has been nullified — i.e., only for the FetcherClient subclass. For a plain FetcherSession used outside its 'with' block, _curl_session stays None and falsy, so this RuntimeError fires. It is marked 'pragma: no cover' because it guards the misuse path.
Source
Thrown at scrapling/engines/static.py:244
Perform an HTTP request using the configured session.
"""
stealth = self._stealth if stealth is None else stealth
selector_config = self._get_param(kwargs, "selector_config", self.selector_config) or self.selector_config
max_retries = self._get_param(kwargs, "retries", self._default_retries)
retry_delay = self._get_param(kwargs, "retry_delay", self._default_retry_delay)
static_proxy = kwargs.pop("proxy", None)
session = self._curl_session
one_off_request = False
if session is _NO_SESSION and self.__enter__ is None:
# For usage inside FetcherClient
# It turns out `curl_cffi` caches impersonation state, so if you turned it off, then on then off, it won't be off on the last time.
session = CurlSession()
one_off_request = True
if not session:
raise RuntimeError("No active session available.") # pragma: no cover
try:
for attempt in range(max_retries):
proxy: Optional[ProxyType]
if self._proxy_rotator and static_proxy is None:
proxy = self._proxy_rotator.get_proxy()
else:
proxy = static_proxy or self._default_proxy
request_args = self._merge_request_args(stealth=stealth, proxy=proxy, **kwargs)
try:
response = session.request(method, **request_args)
assert response is not None
result = ResponseFactory.from_http_request(response, selector_config, meta={"proxy": proxy})
return result
except CurlError as e: # pragma: no cover
if attempt < max_retries - 1:
# Now if the rotator is enabled, we will try again with the new proxyView on GitHub (pinned to 5d213a2d47)
Solutions
- Wrap usage in a context manager: 'with FetcherSession(...) as session: session.get(url)'.
- If you don't want a session lifecycle, use FetcherClient (or AsyncFetcher's one-shot functions) which create one-off sessions automatically.
- Ensure no code path calls request methods after the 'with' block ends (e.g., async callbacks or background threads outliving the block).
Example fix
# before
session = FetcherSession(stealth=True)
resp = session.get('https://example.com') # RuntimeError
# after
with FetcherSession(stealth=True) as session:
resp = session.get('https://example.com') Defensive patterns
Strategy: validation
Validate before calling
def ensure_open(session):
# A usable session is either inside its context or a FetcherClient (one-off mode)
if not getattr(session, '_is_alive', False) and getattr(session, '_curl_session', None) is None:
raise RuntimeError('FetcherSession must be used inside "with"; or switch to FetcherClient')
# usage
with FetcherSession() as session:
ensure_open(session)
session.get(url) Type guard
def has_active_sync_session(session) -> bool:
return getattr(session, '_is_alive', False) is True and getattr(session, '_curl_session', None) is not None Try / catch
try:
resp = session.get(url)
except RuntimeError as e:
if 'No active session' in str(e):
with FetcherSession(**cfg) as s:
resp = s.get(url)
else:
raise Prevention
- Standardize on 'with FetcherSession(...) as session:' immediately after construction.
- For stateless convenience, use FetcherClient / AsyncFetcher top-level functions.
- Lint for request calls that sit outside the context block (e.g., returns of responses after the with ends).
When it happens
Trigger: Creating FetcherSession(...) and calling session.get(url) / .fetch(...) without entering the 'with' block first; calling request methods after __exit__ has already closed and cleared the session; calling methods on a _SyncSessionLogic whose __enter__ raised midway so _curl_session was never assigned.
Common situations: Treating FetcherSession like the older stateless API (pre-context-manager versions allowed direct .get()); refactoring code from FetcherClient to FetcherSession and forgetting the 'with'; calling fetch from a helper that runs after the context block exited.
Related errors
- This FetcherSession instance already has an active synchrono
- Cannot exit invalid session
- This FetcherSession instance already has an active asynchron
- Session has been already started
- Context manager has been closed
AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14).
Data as JSON: /api/errors/07d53ddaeb758428.
Report an issue: GitHub.