element-hq / element-hq/synapse
If the upload of media files exceeds the `max_upload_size`, Synapse terminates the connection without returning an HTTP status code
- Dominant language
- Python
- Stars
- 4.6k
- Forks
- 600
- Avg merge
- 5d 22h
- Merged PRs (30d)
- 51
Description
### Description
If the upload of media files exceeds the `max_upload_size`, Synapse terminates the connection without returning an HTTP status code.
Synapse should respond with the correct status code `HTTP/413`.
Related Issue:
- #17053
### Steps to reproduce
Upload a file larger than limit:
```sh
curl 'https:///_matrix/media/v3/upload?filename=testvideo.mp4' -H 'Authorization: Bearer ' -H 'Content-Type: video/mp4' --data-binary @video.mp4 -v
* Host :443 was resolved.
* IPv6: (none)
* IPv4:
* Trying :443...
* Connected to () port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / X25519 / RSASSA-PSS
* ALPN: server accepted h2
* Server certificate:
* subject: CN=
* start date: Jun 23 10:05:04 2026 GMT
* expire date: Sep 21 10:05:03 2026 GMT
* subjectAltName: host "" matched cert's ""
* issuer: C=US; O=Let's Encrypt; CN=YR1
* SSL certificate verify ok.
* Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 2: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 3: Public key type RSA (4096/152 Bits/secBits), signed using sha256WithRSAEncryption
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https:///_matrix/media/v3/upload?filename=testvideo.mp4
* [HTTP/2] [1] [:method: POST]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: ]
* [HTTP/2] [1] [:path: /_matrix/media/v3/upload?filename=testvideo.mp4]
* [HTTP/2] [1] [user-agent: curl/8.5.0]
* [HTTP/2] [1] [accept: */*]
* [HTTP/2] [1] [authorization: Bearer ]
* [HTTP/2] [1] [content-type: video/mp4]
* [HTTP/2] [1] [content-length: 108864523]
> POST /_matrix/media/v3/upload?filename=testvideo.mp4 HTTP/2
> Host:
> User-Agent: curl/8.5.0
> Accept: */*
> Authorization: Bearer
> Content-Type: video/mp4
> Content-Length: 108864523
>
< HTTP/2 502
< content-length: 11
< date: Thu, 30 Jul 2026 13:30:03 GMT
* HTTP error before end of send, stop sending
<
* Connection #0 to host left intact
```
Ingress/Reverse Proxy terminates with `HTTP/2 502`, because Synapse closes the connection without response.
### Homeserver
private
### Synapse Version
1.157.2
### Installation Method
Docker (matrixdotorg/synapse)
### Database
PostgreSQL
### Workers
Multiple workers
### Platform
Kubernetes
Ingress: Traefik
### Configuration
`max_upload_size: 50M`
### Relevant log output
```shell
2026-07-30 13:30:03,334 - synapse.http.site - 306 - WARNING - sentinel - Aborting connection from IPv4Address(type='TCP', host='100.101.44.7', port=44152) because the request exceeds maximum size: (no method yet) (no uri yet)
2026-07-30 13:30:03,346 - synapse.http.site - 542 - INFO - sentinel - Connection from IPv4Address(type='TCP', host='100.101.44.7', port=44152) lost before request headers were read
```
### Anything else that would be useful to know?
affected code:
https://github.com/element-hq/synapse/blob/36664cac4fdec38993c68078cd9a82452b56dca7/synapse/http/site.py#L302-L315
I’d be happy to post an update. Is this the right place, or is there a more specific section for media uploads?
Contributor guide
Research direction
Start in synapse/http/site.py around lines 302-315, then reproduce the oversized media upload with the curl command from the issue. Trace how the request-size limit is handled and verify that an upload exceeding max_upload_size returns HTTP 413 rather than closing without a response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100