chenhg5/cc-connect · error
matrix: encrypt
Error message
matrix: encrypt: %w
What it means
This error wraps a failure from ch.Encrypt() inside tryEncryptAndSend. After confirming the room is encrypted, the adapter encrypts the event content with Megolm for the target room; if the crypto helper cannot produce encrypted content (no group session, unknown room members, missing outbound session), the send is aborted with this wrapped error instead of sending plaintext.
Solutions
- Ensure crypto init completed (ch.Init succeeded) before sending; log/wait for initial sync and device-list readiness.
- Wait for or force a room-state sync so member device lists are populated, then retry the send.
- Verify members' devices can share keys (cross-signing/verification); run the stale-key re-upload path if server keys are out of sync.
- If persistent, close and recreate the CryptoHelper to rebuild outbound sessions.
- Log the wrapped cause to distinguish 'no Olm session with member' from generic store failures.
Example fix
// before
encContent, err := ch.Encrypt(ctx, roomID, evtType, content)
if err != nil {
return true, fmt.Errorf("matrix: encrypt: %w", err)
}
// after
encContent, err := ch.Encrypt(ctx, roomID, evtType, content)
if err != nil {
slog.Warn("matrix: encrypt failed, will retry after sync", "room", roomID, "err", err)
return true, fmt.Errorf("matrix: encrypt: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// Go: before sending, wait for the helper to be initialized and room state synced
if !p.cryptoReady() { return fmt.Errorf("crypto helper not initialized") }
if !p.isRoomEncrypted(ctx, roomID) { /* skip encryption path */ } Try / catch
sent, err := p.tryEncryptAndSend(ctx, roomID, evtType, content)
if err != nil && strings.Contains(err.Error(), "matrix: encrypt") {
// transient key/state issue: resync room members and retry once
p.resyncRoomState(ctx, roomID)
sent, err = p.tryEncryptAndSend(ctx, roomID, evtType, content)
} Prevention
- Treat 'bot added to encrypted room' as an async event: delay sends until first full sync completes.
- Never delete the crypto DB while the room remains encrypted; back it up instead.
- Enable device-list tracking and key-share responses from your other sessions.
- Add observability around Encrypt failures to distinguish missing-member-keys vs session errors.
When it happens
Trigger: sendRoomEvent → tryEncryptAndSend: isRoomEncrypted returns true and ch.Encrypt(ctx, roomID, evtType, content) returns err — e.g. no outbound Megolm session could be created because room member keys/device lists are unknown, the crypto helper was not fully initialized, or the room state store lacks membership data.
Common situations: Bot was just invited to an encrypted room and has not yet received member device keys; encryption configured server-side but the local crypto DB was deleted so sessions are missing; key share requests from other devices pending/unanswered; room state store not synced before first send.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/767206fbe4d8e44a.
Report an issue: GitHub.
Appendix: source
Thrown at platform/matrix/e2ee.go:239
ch.Close()
client.StateStore = nil
client.Store = mautrix.NewMemorySyncStore()
}
// tryEncryptAndSend attempts to encrypt and send an event if E2EE is available.
// Returns (true, nil) if handled, (true, err) if handled with error, (false, nil) if not handled.
func (p *Platform) tryEncryptAndSend(ctx context.Context, client *mautrix.Client, roomID id.RoomID, evtType event.Type, content any) (bool, error) {
ch := p.getE2EECryptoHelper()
if ch == nil {
return false, nil
}
if !p.isRoomEncrypted(ctx, roomID) {
return false, nil
}
encContent, err := ch.Encrypt(ctx, roomID, evtType, content)
if err != nil {
return true, fmt.Errorf("matrix: encrypt: %w", err)
}
_, err = client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encContent)
if err != nil {
return true, fmt.Errorf("matrix: send encrypted: %w", err)
}
return true, nil
}
func (p *Platform) isRoomEncrypted(ctx context.Context, roomID id.RoomID) bool {
client := p.getClient()
if client == nil || client.StateStore == nil {
return false
}
ss, ok := client.StateStore.(crypto.StateStore)
if !ok {
return false
}
enc, err := ss.IsEncrypted(ctx, roomID)View on GitHub (pinned to 4000b2338a)