signalapp / signalapp/Signal-Android
Rate limit when communicating with one particular person
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 29.4k
- Forks
- 6.9k
- PR merge metrics
- No merged PRs in 30d
Description
Guidelines
- I have searched open and closed issues for duplicates
- I am submitting a bug report for existing functionality that does not work as intended
- This isn't a feature request or a discussion topic
Bug description
When communicating with one particular friend, I would some time hit rate limit and cannot send message (spinning dot do not turn into one check mark)
- This doesn't happen with any other person
- This does happen within group, but message to other people would deliver fine except said person.
- While I am waiting to send my message to said person, said person can send me message and I would recieve them just fine
- While I am waiting to send my message to said person, I can send and recieve messages from other people and group chat just fine.
- Deleting unsend message to said person does not resolve the rate limit
- This issue usually go away over night, and would randomly reoccur every couple of weeks.
Screenshots
No response
Device
Pixel 7a
Android version
16 (Graphene OS without Google Play)
Signal version
8.9.1
Link to debug log
https://debuglogs.org/android/8.9.1/d0dd8e74e5f027868a90e3c118fc577fa790a069bf3c9d0996b3df0feb0303fe
[8.9.1] [49 ] 2026-05-13 22:26:08.647 EDT D SignalServiceMessageSender: [1778725568646] Sending a typing message to 1 recipient(s) using 1:1 messages.
[8.9.1] [49 ] 2026-05-13 22:26:08.647 EDT D SignalServiceMessageSender: [1778725568646] Sending to 1 recipients.
[8.9.1] [18556] 2026-05-13 22:26:08.706 EDT D LibSignalChatConnection: [libsignal-unauth:38049743] [sendRequest] Success: 409
[8.9.1] [694 ] 2026-05-13 22:26:08.709 EDT W SignalServiceMessageSender: [sendMessage][1778725568646] Handling mismatched devices. (StatusCode: 409)
[8.9.1] [694 ] 2026-05-13 22:26:08.709 EDT W SignalServiceMessageSender: [handleMismatchedDevices] Address: ********-****-****-****-*********8db, ExtraDevices: [], MissingDevices: [2]
[8.9.1] [694 ] 2026-05-13 22:26:08.711 EDT D KeysApi: Fetching prekeys for ********-****-****-****-*********8db.2, i.e. GET /v2/keys/********-****-****-****-*********8db/2
[8.9.1] [18557] 2026-05-13 22:26:08.737 EDT D LibSignalChatConnection: [libsignal-auth:604455] [sendRequest] Success: 429
[8.9.1] [694 ] 2026-05-13 22:26:08.738 EDT W SignalServiceMessageSender: [1778725568646] Hit rate limit: ********-****-****-****-*********8db
org.whispersystems.signalservice.api.push.exceptions.RateLimitException: [429] Rate limit exceeded: 429
at org.whispersystems.signalservice.api.NetworkResultUtil.toPreKeysLegacy(NetworkResultUtil.kt:125)
at org.whispersystems.signalservice.api.SignalServiceMessageSender.handleMismatchedDevices(SignalServiceMessageSender.java:3024)
at org.whispersystems.signalservice.api.SignalServiceMessageSender.lambda$sendMessageRx$17(SignalServiceMessageSender.java:2378)
at org.whispersystems.signalservice.api.SignalServiceMessageSender.$r8$lambda$SYPQNQkQYueQagvZ5NsSwnmMvkI(SignalServiceMessageSender.java:0)
at org.whispersystems.signalservice.api.SignalServiceMessageSender$$ExternalSyntheticLambda29.call(R8$$SyntheticClass:0)
at io.reactivex.rxjava3.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:43)
at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
at io.reactivex.rxjava3.internal.operators.single.SingleFlatMap.subscribeActual(SingleFlatMap.java:37)
at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
at io.reactivex.rxjava3.internal.operators.single.SingleResumeNext$ResumeMainSingleObserver.onError(SingleResumeNext.java:80)
at io.reactivex.rxjava3.internal.operators.single.SingleFlatMap$SingleFlatMapCallback$FlatMapSingleObserver.onError(SingleFlatMap.java:117)
at io.reactivex.rxjava3.internal.disposables.EmptyDisposable.error(EmptyDisposable.java:78)
at io.reactivex.rxjava3.internal.operators.single.SingleError.subscribeActual(SingleError.java:41)
at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
at io.reactivex.rxjava3.internal.operators.single.SingleFlatMap$SingleFlatMapCallback.onSuccess(SingleFlatMap.java:85)
at io.reactivex.rxjava3.internal.operators.single.SingleObserveOn$ObserveOnSingleObserver.run(SingleObserveOn.java:81)
at io.reactivex.rxjava3.internal.schedulers.ScheduledDirectTask.call(ScheduledDirectTask.java:38)
at io.reactivex.rxjava3.internal.schedulers.ScheduledDirectTask.call(ScheduledDirectTask.java:25)
at java.util.concurrent.FutureTask.run(FutureTask.java:317)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1154)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:652)
at java.lang.Thread.run(Thread.java:1563)
at org.signal.core.util.concurrent.SignalExecutors$NumberedThreadFactory$1.run(SignalExecutors.java:100)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the debug log and trace the reported path through SignalServiceMessageSender.java, especially handleMismatchedDevices, then inspect NetworkResultUtil.kt and KeysApi around the prekey request. Compare the 409 mismatched-device response with the subsequent 429 rate limit. Done means the recipient-specific send failure is explained and verified against the reported behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- mobile, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100