Limit outgoing to_device EDU size to 65536#18416
Merged
Merged
Conversation
MadLittleMods
added a commit
that referenced
this pull request
Jun 19, 2025
From my review of #18416
Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
Contributor
|
Looks like the CI tests are flaky as mentioned here : #18537 |
Contributor
|
Not able to reproduce the issue here by running |
Contributor
|
Relevant thread is here: #18416 (comment) (press 'load more' when viewing the conversations to get everything visible) We should link your spec PR in the code where we raise |
Contributor
Author
MadLittleMods
approved these changes
Mar 23, 2026
MadLittleMods
left a comment
Contributor
There was a problem hiding this comment.
Looks good. I'm unable to apply the last edits
Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
Contributor
|
Thanks for the fix @MatMaul 🐏 |
Contributor
Author
|
We did it! Thanks for the reviews 🙏 |
MadLittleMods
added a commit
that referenced
this pull request
Mar 24, 2026
Spawning from #18416 (comment)
3 tasks
MadLittleMods
added a commit
that referenced
this pull request
Mar 25, 2026
…clock) (#19602) Spawning from #18416 (comment)
erikjohnston
added a commit
that referenced
this pull request
Mar 27, 2026
This reverts commit 7fad50f.
erikjohnston
added a commit
that referenced
this pull request
Mar 27, 2026
Reverts #18416 Unfortunately, this causes failures on `/sendToDevice` endpoint in normal circumstances. If a single user has, say, a hundred devices then we easily go over the limit. This blocks message sending entirely in encrypted rooms. cc @MadLittleMods @MatMaul
erikjohnston
pushed a commit
that referenced
this pull request
Mar 27, 2026
If a set of messages exceeds this limit, the messages are split across several EDUs. Fix #17035 (should) There is currently [no official specced limit for EDUs](matrix-org/matrix-spec#807), but the consensus seems to be that it would be useful to have one to avoid this bug by bounding the transaction size. As a side effect it also limits the size of a single to-device message to a bit less than 65536. This should probably be added to the spec similarly to the [message size limit.](https://spec.matrix.org/v1.14/client-server-api/#size-limits) Spec PR: matrix-org/matrix-spec#2340 --------- Co-authored-by: mcalinghee <mcalinghee.dev@gmail.com> Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
erikjohnston
added a commit
that referenced
this pull request
Mar 27, 2026
This is based on #18416, which got reverted due to it rejecting to-device messages to users with many devices. The main change here is that if a to-device EDU for a single user is too large, then we split it up into multiple EDUs.
erikjohnston
added a commit
that referenced
this pull request
Mar 27, 2026
This is based on #18416, which got reverted due to it rejecting to-device messages to users with many devices. The main change here is that if a to-device EDU for a single user is too large, then we split it up into multiple EDUs.
erikjohnston
added a commit
that referenced
this pull request
Jun 2, 2026
This is based on #18416, which got reverted (#19614) due to it incorrectly rejecting to-device messages to users with many devices (and thus breaking message sending). Fix #17035 A to-device message content looks like: ```jsonc { "@user:domain": {"device1": {...}, "device2": {...}}, ... } ``` The previous PR would split up into multiple EDUs, each with a subset of the users. However, if one user's entry was too large it would not further split it up and then error out. The main change in this PR is to allow splitting up a single user into multiple EDUs. Other changes: 1. Rename to `SOFT_MAX_EDU_SIZE` to indicate that we sometimes send EDUs with larger size than that, and its more a target than a hard limit. 2. Check early if any to-device message (to a specific device) is too large to send, even if we're not going to send it over federation. This ensures that we catch issues where clients try to send too large to-device. This still means that if a client send a large individual to-device message it will fail, but I don't believe we ever send such large to-device messages (normally they're in the range of a few KB). --- I ended up changing the implementation a bunch to make it easy to reuse the code to split up dictionaries. Instead of repeatedly splitting up the EDU until each bit fits into the size, we instead record the size of each entry in the dict and instead split up based on cumulative size. This means we call `encode_canonical_json` on each entry rather than once on the entire struct, but its not significantly slower to do so. -- cc @MatMaul @MadLittleMods --------- Co-authored-by: Mathieu Velten <matmaul@gmail.com> Co-authored-by: mcalinghee <mcalinghee.dev@gmail.com> Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
FrenchGithubUser
pushed a commit
to famedly/synapse-upstreaming
that referenced
this pull request
Jun 12, 2026
If a set of messages exceeds this limit, the messages are split across several EDUs. Fix element-hq#17035 (should) There is currently [no official specced limit for EDUs](matrix-org/matrix-spec#807), but the consensus seems to be that it would be useful to have one to avoid this bug by bounding the transaction size. As a side effect it also limits the size of a single to-device message to a bit less than 65536. This should probably be added to the spec similarly to the [message size limit.](https://spec.matrix.org/v1.14/client-server-api/#size-limits) Spec PR: matrix-org/matrix-spec#2340 --------- Co-authored-by: mcalinghee <mcalinghee.dev@gmail.com> Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
FrenchGithubUser
pushed a commit
to famedly/synapse-upstreaming
that referenced
this pull request
Jun 12, 2026
FrenchGithubUser
pushed a commit
to famedly/synapse-upstreaming
that referenced
this pull request
Jun 12, 2026
Reverts element-hq#18416 Unfortunately, this causes failures on `/sendToDevice` endpoint in normal circumstances. If a single user has, say, a hundred devices then we easily go over the limit. This blocks message sending entirely in encrypted rooms. cc @MadLittleMods @MatMaul
FrenchGithubUser
pushed a commit
to famedly/synapse-upstreaming
that referenced
this pull request
Jun 12, 2026
This is based on element-hq#18416, which got reverted (element-hq#19614) due to it incorrectly rejecting to-device messages to users with many devices (and thus breaking message sending). Fix element-hq#17035 A to-device message content looks like: ```jsonc { "@user:domain": {"device1": {...}, "device2": {...}}, ... } ``` The previous PR would split up into multiple EDUs, each with a subset of the users. However, if one user's entry was too large it would not further split it up and then error out. The main change in this PR is to allow splitting up a single user into multiple EDUs. Other changes: 1. Rename to `SOFT_MAX_EDU_SIZE` to indicate that we sometimes send EDUs with larger size than that, and its more a target than a hard limit. 2. Check early if any to-device message (to a specific device) is too large to send, even if we're not going to send it over federation. This ensures that we catch issues where clients try to send too large to-device. This still means that if a client send a large individual to-device message it will fail, but I don't believe we ever send such large to-device messages (normally they're in the range of a few KB). --- I ended up changing the implementation a bunch to make it easy to reuse the code to split up dictionaries. Instead of repeatedly splitting up the EDU until each bit fits into the size, we instead record the size of each entry in the dict and instead split up based on cumulative size. This means we call `encode_canonical_json` on each entry rather than once on the entire struct, but its not significantly slower to do so. -- cc @MatMaul @MadLittleMods --------- Co-authored-by: Mathieu Velten <matmaul@gmail.com> Co-authored-by: mcalinghee <mcalinghee.dev@gmail.com> Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
FrenchGithubUser
pushed a commit
to famedly/synapse
that referenced
this pull request
Jun 30, 2026
This is based on element-hq/synapse#18416, which got reverted (#19614) due to it incorrectly rejecting to-device messages to users with many devices (and thus breaking message sending). Fix element-hq/synapse#17035 A to-device message content looks like: ```jsonc { "@user:domain": {"device1": {...}, "device2": {...}}, ... } ``` The previous PR would split up into multiple EDUs, each with a subset of the users. However, if one user's entry was too large it would not further split it up and then error out. The main change in this PR is to allow splitting up a single user into multiple EDUs. Other changes: 1. Rename to `SOFT_MAX_EDU_SIZE` to indicate that we sometimes send EDUs with larger size than that, and its more a target than a hard limit. 2. Check early if any to-device message (to a specific device) is too large to send, even if we're not going to send it over federation. This ensures that we catch issues where clients try to send too large to-device. This still means that if a client send a large individual to-device message it will fail, but I don't believe we ever send such large to-device messages (normally they're in the range of a few KB). --- I ended up changing the implementation a bunch to make it easy to reuse the code to split up dictionaries. Instead of repeatedly splitting up the EDU until each bit fits into the size, we instead record the size of each entry in the dict and instead split up based on cumulative size. This means we call `encode_canonical_json` on each entry rather than once on the entire struct, but its not significantly slower to do so. -- cc @MatMaul @MadLittleMods --------- Co-authored-by: Mathieu Velten <matmaul@gmail.com> Co-authored-by: mcalinghee <mcalinghee.dev@gmail.com> Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

If a set of messages exceeds this limit, the messages are split across several EDUs.
Fix #17035 (should)
There is currently no official specced limit for EDUs, but the consensus seems to be that it would be useful to have one to avoid this bug by bounding the transaction size.
As a side effect it also limits the size of a single to-device message to a bit less than 65536.
This should probably be added to the spec similarly to the message size limit..
Spec PR: matrix-org/matrix-spec#2340
Pull Request Checklist