{"record":{"id":"327a15d4d0b78be6","repo":"chenhg5/cc-connect","slug":"init-crypto-w","errorCode":null,"errorMessage":"init crypto: %w","messagePattern":"init crypto: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/matrix/e2ee.go","lineNumber":215,"sourceCode":"\n\tif err := ch.Init(ctx); err != nil {\n\t\tif !isRetry && strings.Contains(err.Error(), \"not marked as shared\") {\n\t\t\tslog.Warn(\"matrix: stale device keys on server, force-uploading new keys\")\n\t\t\tfunc() {\n\t\t\t\tdefer func() { recover() }()\n\t\t\t\tif mach := ch.Machine(); mach != nil {\n\t\t\t\t\tif shareErr := mach.ShareKeys(ctx, -1); shareErr != nil {\n\t\t\t\t\t\tslog.Error(\"matrix: failed to force-share keys\", \"error\", shareErr)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t\tch.Close()\n\t\t\tclient.StateStore = nil\n\t\t\tclient.Store = mautrix.NewMemorySyncStore()\n\t\t\treturn p.tryInitCrypto(ctx, client, pickleKey, dbPath, true)\n\t\t}\n\t\tp.cleanupFailedCrypto(client, ch)\n\t\treturn nil, fmt.Errorf(\"init crypto: %w\", err)\n\t}\n\treturn ch, nil\n}\n\nfunc (p *Platform) cleanupFailedCrypto(client *mautrix.Client, ch *cryptohelper.CryptoHelper) {\n\tch.Close()\n\tclient.StateStore = nil\n\tclient.Store = mautrix.NewMemorySyncStore()\n}\n\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) {","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/matrix/e2ee.go#L197-L233","documentation":"This error wraps failures from ch.Init(ctx) during Matrix E2EE setup. Init loads/creates the device account, performs key uploads and device-list syncing with the homeserver. If Init fails and it is not the retryable 'not marked as shared' stale-key case, the helper is cleaned up (cleanupFailedCrypto closes the DB and resets client stores) and this wrapped error propagates.","triggerScenarios":"tryInitCrypto calls ch.Init(ctx) and it returns err that either is a retry (isRetry already true) or does not contain 'not marked as shared' — e.g. homeserver API failures during key upload, WHOAMI/keys/query endpoints returning errors, expired/invalid access token, network timeout, or the stale-key retry path also failing.","commonSituations":"Homeserver unreachable or returning 401/403 because the access token was revoked; device keys marked as not shared after server DB restore, and the single forced retry also fails; rate limiting on /keys/upload; TLS/certificate problems between the bridge and homeserver.","solutions":["Check the wrapped cause: verify the access token is valid and the homeserver is reachable (curl the /_matrix/client/versions endpoint).","Restart the platform after clearing stale server-side device keys (delete the device via homeserver admin API) so key upload succeeds.","If the 'not marked as shared' retry already fired and failed, remove the local crypto DB (dbPath) and restart for a clean re-upload.","Inspect slog output around the failure for network/HTTP status details; fix connectivity or TLS trust as indicated.","Update mautrix-go/cryptohelper if the failure is a known compatibility issue with your Synapse/Dendrite version."],"exampleFix":"// before\nif err := ch.Init(ctx); err != nil {\n    return nil, fmt.Errorf(\"init crypto: %w\", err)\n}\n// after\nif err := ch.Init(ctx); err != nil {\n    slog.Error(\"matrix: crypto init failed\", \"err\", err)\n    return nil, fmt.Errorf(\"init crypto: %w\", err) // inspect %w cause for HTTP status / token issues\n}","handlingStrategy":"retry","validationCode":"// Go: pre-check homeserver reachability and token before enabling E2EE\nresp, err := http.Get(homeserver + \"/_matrix/client/versions\")\nif err != nil || resp.StatusCode != 200 {\n    return fmt.Errorf(\"homeserver unreachable before crypto init: status=%v err=%v\", resp, err)\n}","typeGuard":null,"tryCatchPattern":"ch, err := initCrypto(ctx, client, key, dbPath)\nif err != nil && strings.Contains(err.Error(), \"init crypto\") {\n    // one clean retry with a fresh store\n    os.Remove(dbPath)\n    ch, err = initCrypto(ctx, client, key, dbPath)\n    if err != nil {\n        return fmt.Errorf(\"crypto init failed after retry: %w\", err)\n    }\n}","preventionTips":["Rotate access tokens before expiry and re-deploy rather than letting them lapse mid-run.","Keep the crypto DB persistent across restarts to avoid repeated stale-key uploads.","Verify homeserver TLS certificates are trusted by the bridge container.","Watch for /keys/upload rate limits on large deployments and stagger key uploads.","Keep mautrix-go and cryptohelper versions aligned with your homeserver release."],"tags":["matrix","e2ee","homeserver","key-upload"],"backgroundTag":"http-error-response","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"}