oraios/serena · error · SerenaClientError

Request failed: {e}

Error message

Request failed: {e}

What it means

The final catch-all in _make_request: any other requests.exceptions.RequestException (not ConnectionError/Timeout/HTTPError — e.g. TooManyRedirects, ChunkedEncodingError, InvalidURL) is re-raised as SerenaClientError('Request failed: {e}').

Source

Thrown at src/serena/jetbrains/jetbrains_plugin_client.py:359

            raise ConnectionError(f"Failed to connect to Serena service at {url}: {e}")
        except requests.exceptions.Timeout as e:
            raise ConnectionError(f"Request to {url} timed out: {e}")
        except requests.exceptions.HTTPError as e:
            if response is not None:
                # check for recoverable error (i.e. errors where the problem can be resolved by the caller or
                # other errors where the error text shall simply be passed on to the LLM).
                # The plugin returns 400 for such errors (typically illegal arguments, e.g. non-unique name path)
                # but only since version 2023.2.6
                if self.is_version_at_least(2023, 2, 6):
                    is_recoverable_error = response.status_code == 400
                else:
                    is_recoverable_error = True  # assume recoverable for older versions (mix of errors)
                if is_recoverable_error:
                    raise APIError(response)
                raise PluginServerError(f"API request failed with status {response.status_code}: {response.text}")
            raise PluginServerError(f"API request failed with HTTP error: {e}")
        except requests.exceptions.RequestException as e:
            raise SerenaClientError(f"Request failed: {e}")

    @staticmethod
    def _pythonify_response(response: T) -> T:
        """
        Converts dictionary keys from camelCase to snake_case recursively.

        :response: the response in which to convert keys (dictionary or list)
        """
        to_snake_case = lambda s: "".join(["_" + c.lower() if c.isupper() else c for c in s])

        def convert(x):
            if isinstance(x, dict):
                return {to_snake_case(k): convert(v) for k, v in x.items()}
            elif isinstance(x, list):
                return [convert(item) for item in x]
            else:
                return x

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Inspect the wrapped exception message for the underlying cause
  2. Re-run from_project to rediscover a valid service URL
  3. Fix proxy environment variables affecting localhost
  4. Restart the IDE and retry the operation
Defensive patterns

Strategy: try-catch

Validate before calling

# validate the discovered service URL before use
from urllib.parse import urlparse
def valid_service_url(url: str) -> bool:
    p = urlparse(url)
    return p.scheme in ("http", "https") and bool(p.hostname) and p.port is not None

Try / catch

try:
    client = JetBrainsPluginClient.from_project(project)
    refs = client.find_references(name_path="Foo")
except SerenaClientError as e:
    if "Request failed" in str(e):
        log.error("Underlying requests error: %s — rediscover service and retry", e)
        client = JetBrainsPluginClient.from_project(project)
    else:
        raise

Prevention

When it happens

Trigger: Unusual requests-library failures during plugin API calls — malformed service URL, too many redirects, response decoding errors — from client init or symbol/reference operations.

Common situations: Bad discovered service URL (whitespace/garbage port); proxy misconfiguration; interrupted local HTTP stream when the IDE is killed mid-response.

Related errors


AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29). Data as JSON: /api/errors/1e10740b1cbff197. Report an issue: GitHub.