sipeed/picoclaw · error
decrypt matrix media: %w
Error message
decrypt matrix media: %w
What it means
Thrown by MatrixChannel.downloadMedia when an inbound attachment is encrypted (msgEvt.File set, msgEvt.URL empty) and msgEvt.File.PrepareForDecryption fails (pkg/channels/matrix/matrix.go:1026). PrepareForDecryption parses the EncryptedFile JWK — key, iv, v, hashes.sha256 — and rejects malformed metadata: wrong key/IV lengths, missing hashes, or an unparseable JWK. The HTTP download already succeeded at this point; only client-side AES-CTR/Olm-style attachment decryption setup failed.
Source
Thrown at pkg/channels/matrix/matrix.go:1026
if ctx != nil {
dlCtx = ctx
}
reqCtx, cancel := context.WithTimeout(dlCtx, 20*time.Second)
defer cancel()
resp, err := c.client.Download(reqCtx, parsed)
if err != nil {
return "", err
}
defer resp.Body.Close()
reader := resp.Body
readerClose := func() error { return nil }
// Encrypted attachments put URL in msgEvt.File and require client-side decryption.
if msgEvt != nil && msgEvt.File != nil && msgEvt.URL == "" {
if err = msgEvt.File.PrepareForDecryption(); err != nil {
return "", fmt.Errorf("decrypt matrix media: %w", err)
}
decryptReader := msgEvt.File.DecryptStream(resp.Body)
reader = decryptReader
readerClose = decryptReader.Close
}
label := matrixMediaLabel(msgEvt, mediaKind)
ext := matrixMediaExt(label, matrixContentType(msgEvt), mediaKind)
mediaDir, err := matrixMediaTempDir()
if err != nil {
return "", fmt.Errorf("create matrix media directory: %w", err)
}
tmp, err := os.CreateTemp(mediaDir, "matrix-media-*"+ext)
if err != nil {
return "", err
}
tmpPath := tmp.Name()
cleanup := trueView on GitHub (pinned to 49183d7e8d)
Solutions
- Inspect the event's file JSON: verify v=='v1', url is mxc, key.kty/alg/op/extractable shape, iv base64 16 bytes, hashes.sha256 present
- If metadata is malformed, skip the attachment and notify — retrying cannot fix remote content
- Confirm senders use spec-compliant attachment encryption (Matrix v1.1+ 'm.megolm-backup' era EncryptedFile shape)
- Check the bot can decrypt this room's events at all (crypto helper initialized, room keys received) — if the Olm layer is broken, plain files still work while encrypted ones fail elsewhere
Example fix
// before
if err = msgEvt.File.PrepareForDecryption(); err != nil {
return "", fmt.Errorf("decrypt matrix media: %w", err)
}
// after: skip malformed encrypted attachments without failing the handler
if err = msgEvt.File.PrepareForDecryption(); err != nil {
logger.WarnCF("matrix", "undecryptable attachment", map[string]any{"error": err.Error()})
return "", &SkipAttachmentError{Cause: err} // caller notifies user, continues processing text Defensive patterns
Strategy: fallback
Validate before calling
// structural pre-check of the encrypted-file JWK before attempting decryption
func encryptedFileWellFormed(f *event.EncryptedFile) bool {
return f != nil && f.Key != nil && len(f.Key.K) > 0 &&
len(f.IV) > 0 && f.Hashes != nil && f.Hashes.SHA256 != ""
} Try / catch
path, err := c.downloadMedia(ctx, msgEvt, mediaKind)
if err != nil {
var decErr *EncryptedMediaError // wrap downloadMedia's result in a typed error at your boundary
if errors.As(err, &decErr) {
notifyUser("attachment could not be decrypted; asking sender to re-send") // degrade, keep flow alive
return nil, nil
}
return nil, err
} Prevention
- Skip-and-notify on undecryptable attachments instead of failing the whole inbound message
- Verify crypto helper init succeeded at startup — a broken Olm session shifts failures here
- Track decrypt-failure rates per sender/room to spot broken bridges early
- Never retry decryption of malformed metadata: the remote content will not change
When it happens
Trigger: An m.room.encrypted media event whose file object lacks hashes or has a truncated key/iv; bridges or custom clients writing non-spec encrypted attachment metadata; event content mangled by a relay; a msgEvt.File built without URL inside, causing downstream decrypt errors after PrepareForDecryption.
Common situations: Receiving encrypted media from non-Element clients with divergent attachment encryption; bridge software that forwards file metadata incompletely; adversarial/malformed events; older spec drafts (v field missing) from ancient clients.
Related errors
- execute %s: %w
- empty matrix media URL
- invalid matrix media URL: %s
- create crypto helper: %w
- init crypto helper: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/908301e7cd1b6825.
Report an issue: GitHub.