chenhg5/cc-connect · error
weixin: push budget exhausted (%d push messages in the last
Error message
weixin: push budget exhausted (%d push messages in the last %s); ilink throttles the bot after roughly 5-6 pushes per window — reduce messages or re-login later
What it means
checkSendQuota enforces a sliding-window push budget because the ilink backend throttles the bot after roughly 5-6 pushed (non-reply) messages per window. When the number of recorded pushes within sendQuotaWindow reaches the limit, further pushes are rejected with this explanatory error.
Source
Thrown at platform/weixin/weixin.go:796
cutoff := now.Add(-p.sendQuotaWindow)
kept := p.sendQuotaTimes[:0]
for _, t := range p.sendQuotaTimes {
if t.After(cutoff) {
kept = append(kept, t)
}
}
p.sendQuotaTimes = kept
if len(p.sendQuotaTimes) >= p.sendQuotaLimit {
p.sendQuotaMu.Unlock()
pushBudgetExceededCounter.Add(1)
slog.Error("weixin: push_path_budget_exceeded",
"path", string(path),
"used", len(p.sendQuotaTimes),
"limit", p.sendQuotaLimit,
"window", p.sendQuotaWindow.String(),
"hint", "ilink throttles the bot after roughly 5-6 pushes per window — reduce cron/timer pushes or re-login later",
)
return fmt.Errorf("weixin: push budget exhausted (%d push messages in the last %s); "+
"ilink throttles the bot after roughly 5-6 pushes per window — reduce messages or re-login later", p.sendQuotaLimit, p.sendQuotaWindow)
}
p.sendQuotaTimes = append(p.sendQuotaTimes, now)
p.sendQuotaMu.Unlock()
return nil
}
func (p *Platform) sendChunks(ctx context.Context, replyCtx any, content string, path sendPath) error {
rc, ok := replyCtx.(*replyContext)
if !ok || rc == nil {
return fmt.Errorf("weixin: invalid reply context")
}
if err := p.checkSendQuota(ctx, path); err != nil {
return err
}
if strings.TrimSpace(rc.contextToken) == "" {
rc.contextToken = p.getContextToken(rc.peerUserID)
}View on GitHub (pinned to 4000b2338a)
Solutions
- Reduce the number of pushed messages per window or batch content into one message
- Increase sendQuotaLimit via configuration if acceptable for the account
- Have the user message the bot and use Reply (replies bypass the push quota)
- Wait until the sliding window expires and re-send
Defensive patterns
Strategy: retry
Validate before calling
// check quota pressure before pushing
count, window := p.PushQuotaUsage() // if exposed
if count >= limit {
return fmt.Errorf("push budget %d/%d used in %s; defer send", count, limit, window)
} Try / catch
err := p.Send(ctx, rc, content)
if err != nil && strings.Contains(err.Error(), "push budget exhausted") {
time.Sleep(window)
return p.Send(ctx, rc, content)
} Prevention
- Batch multiple notifications into one message
- Prefer Reply over proactive Send (replies bypass the quota)
- Keep per-window pushes to ≤5
- Schedule cron/timer output with jitter to avoid bursts
When it happens
Trigger: Send() (push path) is called more than sendQuotaLimit times within sendQuotaWindow, e.g. cron/timer jobs firing several messages back-to-back. Reply() bypasses this quota via sendPath.
Common situations: Multiple cron jobs or timers dispatching results simultaneously; a long agent output chunked into several pushes; burst of automated notifications after re-login; quota limits left at defaults while message volume grew.
Related errors
- -2
- -2
- weixin: convert %s to AMR: %w
- weixin: token is required (ilink bot Bearer token)
- weixin: create state dir: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/ac16b88ab789ca4c.
Report an issue: GitHub.