{"record":{"id":"df8ac563e5ef0069","repo":"chenhg5/cc-connect","slug":"matrix-send-encrypted-w","errorCode":null,"errorMessage":"matrix: send encrypted: %w","messagePattern":"matrix: send encrypted: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/matrix/e2ee.go","lineNumber":243,"sourceCode":"\n// tryEncryptAndSend attempts to encrypt and send an event if E2EE is available.\n// Returns (true, nil) if handled, (true, err) if handled with error, (false, nil) if not handled.\nfunc (p *Platform) tryEncryptAndSend(ctx context.Context, client *mautrix.Client, roomID id.RoomID, evtType event.Type, content any) (bool, error) {\n\tch := p.getE2EECryptoHelper()\n\tif ch == nil {\n\t\treturn false, nil\n\t}\n\tif !p.isRoomEncrypted(ctx, roomID) {\n\t\treturn false, nil\n\t}\n\n\tencContent, err := ch.Encrypt(ctx, roomID, evtType, content)\n\tif err != nil {\n\t\treturn true, fmt.Errorf(\"matrix: encrypt: %w\", err)\n\t}\n\t_, err = client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encContent)\n\tif err != nil {\n\t\treturn true, fmt.Errorf(\"matrix: send encrypted: %w\", err)\n\t}\n\treturn true, nil\n}\n\nfunc (p *Platform) isRoomEncrypted(ctx context.Context, roomID id.RoomID) bool {\n\tclient := p.getClient()\n\tif client == nil || client.StateStore == nil {\n\t\treturn false\n\t}\n\tss, ok := client.StateStore.(crypto.StateStore)\n\tif !ok {\n\t\treturn false\n\t}\n\tenc, err := ss.IsEncrypted(ctx, roomID)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn enc","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/matrix/e2ee.go#L225-L261","documentation":"This error wraps a failure from client.SendMessageEvent when delivering an already-encrypted event (type m.room.encrypted) to the homeserver. The content encrypted fine, but the HTTP transaction to send it failed, so the message was not delivered.","triggerScenarios":"sendRoomEvent → tryEncryptAndSend: encryption succeeded, then client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encContent) returns err — network failure, homeserver 4xx/5xx (e.g. 403 forbidden because the bot is not joined to the room, 429 rate limit), or request timeout.","commonSituations":"Bot invite not yet accepted so the homeserver rejects the send (M_FORBIDDEN); homeserver outage or restart mid-send; network partition between bridge and homeserver; hitting sync/send rate limits in a busy room.","solutions":["Check the wrapped cause for an HTTP status: 403 means join the room first (verify auto-join completed), 429 means back off and retry per Retry-After.","Verify connectivity to the homeserver (curl /_matrix/client/versions) and retry the send.","Ensure the room ID is correct and the bot account is a joined member of that room.","Implement/raise retry with backoff for transient 5xx/network errors before surfacing to the user.","Check homeserver logs for the corresponding request rejection if client-side details are insufficient."],"exampleFix":"// before\n_, err = client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encContent)\nif err != nil {\n    return true, fmt.Errorf(\"matrix: send encrypted: %w\", err)\n}\n// after\n_, err = client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encContent)\nif err != nil {\n    if errors.Is(err, mautrix.MForbidden) {\n        slog.Warn(\"matrix: not allowed to send, bot may not be joined\", \"room\", roomID)\n    }\n    return true, fmt.Errorf(\"matrix: send encrypted: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// Go: verify bot membership before attempting an encrypted send\nmembers, err := client.JoinedMembers(ctx, roomID)\nif err != nil || !containsUser(members, client.UserID) {\n    return fmt.Errorf(\"bot not joined to %s; skipping encrypted send\", roomID)\n}","typeGuard":null,"tryCatchPattern":"_, err = client.SendMessageEvent(ctx, roomID, event.EventEncrypted, encContent)\nvar httpErr mautrix.HTTPError\nif errors.As(err, &httpErr) {\n    switch httpErr.Response.StatusCode {\n    case 403: // join room / fix permissions then retry\n    case 429: // honor Retry-After then retry\n    default:  // surface with backoff\n    }\n}","preventionTips":["Confirm auto-join completed before the first outbound message to a new room.","Add exponential backoff for transient homeserver 5xx and network errors.","Cap concurrent sends per room to avoid 429 rate limits.","Alert on repeated SendMessageEvent failures as a homeserver health signal."],"tags":["matrix","homeserver","http","send-message"],"backgroundTag":"http-request-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}