From 6ef15a9581e8d260d1c3ed652ea8ceaee4729e9b Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Tue, 26 May 2026 18:24:31 +0100 Subject: [PATCH] Promote InvalidResponseError to a 'real' error type --- synapse/api/errors.py | 59 ++++++++++++++++++++++++- synapse/federation/federation_client.py | 7 +-- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/synapse/api/errors.py b/synapse/api/errors.py index 0c35b4a7ba..cd1548259a 100644 --- a/synapse/api/errors.py +++ b/synapse/api/errors.py @@ -806,7 +806,18 @@ class FederationPullAttemptBackoffError(RuntimeError): class HttpResponseException(CodeMessageException): """ - Represents an HTTP-level failure of an outbound request + Represents an HTTP-level failure of an outbound request, + where the response has an unexpected status code. + + The response may contain a JSON-encoded Matrix API error + with an `errcode` and `error`, but this is optional. + + Analogous to `InvalidResponseError`, but at the response code level + rather than the response body level. + + Should not be allowed to bubble to an API response without handling. + If it does, it will yield a 500 Internal Server Error as any other + unhandled exception. Attributes: response: body of response @@ -824,7 +835,7 @@ class HttpResponseException(CodeMessageException): self.response = response def to_synapse_error(self) -> SynapseError: - """Make a SynapseError based on an HTTPResponseException + """Make a SynapseError based on an HttpResponseException This is useful when a proxied request has failed, and we need to decide how to map the failure onto a matrix error to send back to the @@ -856,6 +867,50 @@ class HttpResponseException(CodeMessageException): return ProxiedRequestError(self.code, errmsg, errcode, j) +class InvalidResponseError(RuntimeError): + """ + Represents a failure to parse/validate the body returned + by an outbound request. + Analogous to `HttpResponseException`, but at the response body level + rather than the response code level. + + Like `HttpResponseException`, should not be allowed to bubble to + an API response without handling. + If it does, it will yield a 500 Internal Server Error as any other + unhandled exception. + + Attributes: + response: body of response + """ + + def __init__(self, msg: str): + """ + Args: + msg: A message for logging purposes. + """ + super().__init__(msg) + + def to_synapse_error(self) -> SynapseError: + """Make a SynapseError based on this error. + + The errcode is set to M_UNKNOWN + and the error message is set to a generic message. + The detail message of this error is not exposed. + + (Maybe we could consider exposing the violating server's name in + the error message.) + + Returns: + The error converted to a SynapseError. + """ + + return ProxiedRequestError( + HTTPStatus.BAD_GATEWAY, + "Remote server presented an invalid response over federation.", + Codes.UNKNOWN, + ) + + class HomeServerNotSetupException(Exception): """ Raised when an operation is attempted on the HomeServer before setup() has been called. diff --git a/synapse/federation/federation_client.py b/synapse/federation/federation_client.py index 2b5ef5fbac..0ca2c61c14 100644 --- a/synapse/federation/federation_client.py +++ b/synapse/federation/federation_client.py @@ -48,6 +48,7 @@ from synapse.api.errors import ( Codes, FederationDeniedError, HttpResponseException, + InvalidResponseError, RequestSendFailed, SynapseError, UnsupportedRoomVersionError, @@ -104,12 +105,6 @@ class PulledPduInfo: pull_origin: str -class InvalidResponseError(RuntimeError): - """Helper for _try_destination_list: indicates that the server returned a response - we couldn't parse - """ - - @attr.s(slots=True, frozen=True, auto_attribs=True) class SendJoinResult: # The event to persist.