{"record":{"id":"b390c3236d46a430","repo":"sipeed/picoclaw","slug":"init-crypto-helper-w","errorCode":null,"errorMessage":"init crypto helper: %w","messagePattern":"init crypto helper: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/matrix/matrix.go","lineNumber":382,"sourceCode":"\t}\n\n\tcryptoHelper, err := cryptohelper.NewCryptoHelper(c.client, []byte(c.config.CryptoPassphrase), wrappedDB)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create crypto helper: %w\", err)\n\t}\n\n\tif c.client.DeviceID == \"\" {\n\t\tresp, whoamiErr := c.client.Whoami(ctx)\n\t\tif whoamiErr != nil {\n\t\t\t_ = db.Close()\n\t\t\treturn fmt.Errorf(\"get device ID via whoami: %w\", whoamiErr)\n\t\t}\n\t\tc.client.DeviceID = resp.DeviceID\n\t}\n\n\tif err = cryptoHelper.Init(ctx); err != nil {\n\t\tcryptoHelper.Close()\n\t\treturn fmt.Errorf(\"init crypto helper: %w\", err)\n\t}\n\n\tc.client.Crypto = cryptoHelper\n\tc.cryptoHelper = cryptoHelper\n\n\tlogger.InfoC(\"matrix\", \"Crypto helper initialized successfully\")\n\treturn nil\n}\n\nfunc markdownToHTML(md string) string {\n\textensions := (parser.CommonExtensions | parser.NoEmptyLineBeforeBlock) &^ parser.DefinitionLists\n\tp := parser.NewWithExtensions(extensions)\n\trenderer := mdhtml.NewRenderer(mdhtml.RendererOptions{Flags: mdhtml.UseXHTML})\n\treturn strings.TrimSpace(string(markdown.ToHTML([]byte(md), p, renderer)))\n}\n\nfunc (c *MatrixChannel) Send(ctx context.Context, msg bus.OutboundMessage) ([]string, error) {\n\tif !c.IsRunning() {","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/matrix/matrix.go#L364-L400","documentation":"Thrown by MatrixChannel.initCrypto when cryptoHelper.Init fails (pkg/channels/matrix/matrix.go:382). Init loads or creates the Olm account in the SQLite store, runs crypto DB migrations, uploads device identity keys to the homeserver (POST /_matrix/client/v3/keys/upload), and starts key-share request loops. So the error mixes local store failures (unreadable pickle because the passphrase changed, failed schema migration) and server-side failures (keys/upload 4xx/5xx, network). cryptoHelper.Close() runs first, then startup aborts.","triggerScenarios":"An existing crypto DB whose Olm account was pickled with a different CryptoPassphrase than the one now configured; crypto DB schema written by an older/newer mautrix version so migration fails; homeserver rejecting /keys/upload (frozen account, misconfigured rate limits, auth mid-expiry); network outage during key upload; SQLite errors on the crypto DB (permissions, corruption).","commonSituations":"Rotating the crypto passphrase without deleting the old crypto DB; upgrading mautrix/bot versions with a stale crypto DB; homeserver temporarily down right when the bot starts; moving the crypto DB file between hosts with different SQLite versions.","solutions":["Read the wrapped error first — 'pickle'/'account' points to a passphrase mismatch, 'migration'/'no such table' to schema version skew, HTTP status codes to homeserver problems","If the passphrase changed or migration is impossible, archive/delete the crypto DB directory and restart — the bot creates fresh device keys (users must re-verify the device; old encrypted history stays undecryptable for it)","Keep maunium.net/go/mautrix and this bot's versions in lockstep when carrying a crypto DB forward","For homeserver-side failures, verify /keys/upload works (network, auth token still valid) and retry startup"],"exampleFix":"# before: passphrase changed but old crypto state kept\n crypto_passphrase: \"new-secret\"   # Init fails: cannot unpickle account\n\n# after: rotate state together with the passphrase\n crypto_passphrase: \"new-secret\"\n mv /var/lib/bot/crypto /var/lib/bot/crypto.bak  # bot re-registers device keys on next start","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := matrixCh.Start(ctx); err != nil {\n\tmsg := err.Error()\n\tswitch {\n\tcase strings.Contains(msg, \"unpickle\"), strings.Contains(msg, \"pickle key\"): // passphrase changed vs stored account\n\t\tarchiveCryptoDb() // move dir aside; device re-registers, users re-verify\n\t\treturn matrixCh.Start(ctx)\n\tcase strings.Contains(msg, \"migration\"), strings.Contains(msg, \"no such table\"): // version skew\n\t\tlog.Fatal(\"crypto db schema incompatible; upgrade path required: \", err)\n\tdefault: // network / keys-upload: safe to retry with backoff\n\t\treturn backoff.Retry(func() error { return matrixCh.Start(ctx) }, policy)\n\t}\n}","preventionTips":["Rotate CryptoPassphrase and crypto DB together — never one without the other","Back up the crypto DB before every bot upgrade that bumps mautrix","Test startup against a copy of the production crypto DB in staging first","Alert on 'init crypto helper' failures: they disable all E2EE for the session"],"tags":["go","matrix","crypto","olm","migration","homeserver","initialization"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}