sipeed/picoclaw · error · channels.ErrTemporary
matrix send: %w
Error message
matrix send: %w
What it means
Thrown by MatrixChannel.Send when mautrix's SendMessageEvent (PUT /_matrix/client/v3/rooms/{roomID}/send/m.room.message) fails (pkg/channels/matrix/matrix.go:435). The channel deliberately classifies the failure as channels.ErrTemporary so the manager retries with exponential backoff. Caveat for debugging: on this exact path the underlying client error is dropped — the wrap contains only ErrTemporary and nothing is logged in Send — so the true cause must be found in homeserver logs or client-level logging.
Source
Thrown at pkg/channels/matrix/matrix.go:435
if err != nil {
return nil, err
}
return []string{msgID}, nil
}
}
trackedMsgID, hasTrackedMsg := c.currentToolFeedbackMessage(msg.ChatID)
if !isToolFeedback {
if msgIDs, handled := c.FinalizeToolFeedbackMessage(ctx, msg); handled {
return msgIDs, nil
}
}
if isToolFeedback {
content = channels.InitialAnimatedToolFeedbackContent(content)
}
resp, err := c.client.SendMessageEvent(ctx, roomID, event.EventMessage, c.messageContent(content))
if err != nil {
return nil, fmt.Errorf("matrix send: %w", channels.ErrTemporary)
}
msgID := resp.EventID.String()
if isToolFeedback {
c.RecordToolFeedbackMessage(msg.ChatID, msgID, msg.Content)
} else if hasTrackedMsg {
c.dismissTrackedToolFeedbackMessage(ctx, msg.ChatID, trackedMsgID)
}
return []string{msgID}, nil
}
func (c *MatrixChannel) messageContent(text string) *event.MessageEventContent {
mc := &event.MessageEventContent{MsgType: event.MsgText, Body: text}
if c.config.MessageFormat != "plain" {
mc.Format = event.FormatHTML
mc.FormattedBody = markdownToHTML(text)
}
return mc
}View on GitHub (pinned to 49183d7e8d)
Solutions
- Enable mautrix client debug logging or check homeserver access logs to recover the dropped cause
- If 429: slow the send rate, batch/dedupe tool-feedback updates (the progress-update path reduces message volume)
- If 403/room gone: re-invite the bot to the room, join it, and stop retrying that ChatID — check room membership with the client before further sends
- If token revoked: re-login and restart the channel
- For genuine transients, do nothing — the manager's exponential backoff already handles it
Example fix
// before: cause dropped
resp, err := c.client.SendMessageEvent(ctx, roomID, event.EventMessage, c.messageContent(content))
if err != nil {
return nil, fmt.Errorf("matrix send: %w", channels.ErrTemporary)
}
// after: keep the cause while preserving retry semantics
if err != nil {
var httpErr mautrix.HTTPError
if errors.As(err, &httpErr) && httpErr.RespError != nil {
logger.ErrorCF("matrix", "send failed", map[string]any{"room": roomID, "err": httpErr.RespError.Errcode})
}
return nil, fmt.Errorf("matrix send: %w: %v", channels.ErrTemporary, err)
} Defensive patterns
Strategy: retry
Try / catch
ids, err := matrixCh.Send(ctx, msg)
if err == nil { return }
if errors.Is(err, channels.ErrTemporary) {
// manager already retries with exponential backoff; ensure your loop does not double-send on success-after-retry without dedupe
return
}
if errors.Is(err, channels.ErrSendFailed) {
deadLetter(msg)
} Prevention
- Enable homeserver-side or mautrix client logging — this wrap drops the underlying cause
- Pace sends (especially animated tool-feedback) to stay under 429 limits
- Periodically verify room membership for active ChatIDs so kicked-from-room 403s stop retry loops
- Deduplicate by content so backoff retries after a timeout don't double-post
When it happens
Trigger: Homeserver rate limiting (429 M_LIMIT_EXCEEDED) after burst sends or animated tool-feedback updates; transient network timeouts/5xx; but also permanent conditions misclassified as temporary: bot was kicked/banned from the room (403 M_FORBIDDEN), room not found, access token revoked mid-session — these will fail every retry.
Common situations: High-volume bot traffic hitting per-user rate limits; a room admin kicking the bot while conversations continue; homeserver restart/overload; expired token after long uptime. Retries eventually succeed for 429/5xx but loop uselessly on 403.
Related errors
- matrix send media: %w
- matrix upload media: %w
- API error %d: %s
- after %d retries: %w
- LLM call failed after retries: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/4e0b2a1d999938ee.
Report an issue: GitHub.