fix(weixin): unrecoverable prepare failed is a session error, not a rate limit that opens the breaker (#80125, salvage #80152) - #115359
Merged
kshitijk4poor merged 3 commits intoSep 18, 2026
Conversation
…ion error, not a rate limit (NousResearch#80125) iLink answers a bot-initiated send with ret=-2 errmsg="prepare failed" when the peer's session is not ready (no inbound message yet, or the context token is gone). That is deterministic: treating it as a frequency limit spent the retry budget on an error that never clears and opened the 30 s rate-limit breaker for the whole account, blocking every later send (NousResearch#80125, NousResearch#112709). After the tokenless re-send (46ab37c) has been tried — or when there is no token to drop — a stale-session -2 now fails fast with a descriptive "session not ready" error and never reaches the rate-limit path. The text avoids the "rate limit" substring classify_send_error keys on. Salvage of NousResearch#80152 (fail fast + keep the breaker closed); NousResearch#80156 arrived five minutes later with the same change. Co-authored-by: RelaxJonh <92573950+RelaxJonh@users.noreply.github.com>
…message keeps the raw fields; test + docs _send_file hit the identical stale -2 after its own tokenless re-send and still raised the generic "sendmessage error"; it now raises the shared _session_not_ready_error. The genuine rate-limit cooldown message carries ret/errcode/errmsg so operators can tell a real -2 frequency limit from the session case. One parametrised test (stored token / no token) asserts the send fails once, classify_send_error does not call it rate_limited, and the breaker stays closed; troubleshooting row in the Weixin docs.
kshitijk4poor
force-pushed
the
fix/weixin-prepare-failed-not-rate-limit
branch
from
September 18, 2026 21:28
60494d8 to
0245267
Compare
kshitijk4poor
enabled auto-merge (rebase)
September 18, 2026 21:45
This was referenced Sep 18, 2026
Closed
Closed
13 tasks
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.
Weixin proactive sends that fail with
ret=-2 errmsg=prepare failed(orunknown error) and cannot be recovered are now reported once as a session problem, instead of being retried as a rate limit, opening the 30 s rate-limit breaker and blocking every later send to that account.Root cause:
_send_text_chunktreated every non-zeroretthat survived the stale-session recovery attempt as a rate limit.ret=-2 prepare failedis deterministic (the iLink session for that chat is not ready / the user never opened the conversation), so the retry budget was spent on an error that never clears and the breaker tripped (#80125; #112709 reports the same shape for cron deliveries). #113069 (landed 2026-09-16) added the tokenless re-send; this handles what happens when that re-send also fails or there was no token to drop.gateway/platforms/weixin.py: when the response is a stale-session variant (-2) and there is no context token to drop or the token-less resend already failed, raiseiLink sendmessage session not ready: …once and stop;-14and genuineret=-13rate limits keep their existing paths. The text deliberately avoids therate limitsubstringclassify_send_errorkeys on, so it lands in the generic lane rather than the rate-limited redelivery lane. Both predicates (_is_session_expired,_is_stale_session_ret) now read the sameerrmsg/msgvalue. The media leg (_send_file) raises the same error for the same response; the genuine rate-limit cooldown message carries the rawret/errcode/errmsg.tests/gateway/test_weixin.py): the send fails immediately, the error is not classifiedrate_limited, the breaker stays closed. Red onorigin/main.website/docs/user-guide/messaging/weixin.mdtroubleshooting row.Salvage of #80152 by @x7peeps (2026-08-06, the first PR to fail fast and keep the breaker closed for this response; reconstructed onto current
mainwith their authorship since the retry ladder changed under #113069) withCo-authored-by@JonthanaHanh for #80156 (same change, five minutes later). The follow-up commit (media leg, cooldown fields, test, docs) is mine.ret=-2 errmsg=prepare failediLink stub onorigin/main→rate limited; cooldown 30s, breaker open; on this branch →iLink sendmessage session not ready: ret=-2 …, breaker closed, next send to the account proceedstest_weixin.py,test_weixin_typing.py,test_weixin_secret_scope.py— 58 passedRelated open PRs on the same symptom (#91647, #100815, #85735, #80426, #74572, #81734, #96437, #101055) will be closed with credit once this lands; most of them are already covered by #113069.