sipeed/picoclaw · error
create crypto helper: %w
Error message
create crypto helper: %w
What it means
Thrown by MatrixChannel.initCrypto when cryptohelper.NewCryptoHelper (pkg/channels/matrix/matrix.go:368) rejects its arguments while constructing the mautrix crypto helper that persists Olm/Megolm sessions in the SQLite DB. The helper encrypts the stored Olm account with a pickle key derived from config.CryptoPassphrase. It errors when the mautrix client is nil, the pickle key/passphrase is empty, or the wrapped DB is nil. Note initCrypto is only called when CryptoPassphrase != "" (matrix.go:271), so a whitespace-only passphrase or a failed client construction are the realistic causes.
Source
Thrown at pkg/channels/matrix/matrix.go:368
"PRAGMA busy_timeout = 5000",
}
for _, pragma := range pragmaStmts {
if _, err = db.ExecContext(ctx, pragma); err != nil {
_ = db.Close()
return fmt.Errorf("execute %s: %w", pragma, err)
}
}
// Wrap with dbutil for dialect support
wrappedDB, err := dbutil.NewWithDB(db, sqliteDriver)
if err != nil {
_ = db.Close()
return fmt.Errorf("wrap database: %w", err)
}
cryptoHelper, err := cryptohelper.NewCryptoHelper(c.client, []byte(c.config.CryptoPassphrase), wrappedDB)
if err != nil {
return fmt.Errorf("create crypto helper: %w", err)
}
if c.client.DeviceID == "" {
resp, whoamiErr := c.client.Whoami(ctx)
if whoamiErr != nil {
_ = db.Close()
return fmt.Errorf("get device ID via whoami: %w", whoamiErr)
}
c.client.DeviceID = resp.DeviceID
}
if err = cryptoHelper.Init(ctx); err != nil {
cryptoHelper.Close()
return fmt.Errorf("init crypto helper: %w", err)
}
c.client.Crypto = cryptoHelper
c.cryptoHelper = cryptoHelperView on GitHub (pinned to 49183d7e8d)
Solutions
- Set a real, non-blank crypto passphrase (strings.TrimSpace it at config load) in the matrix channel config
- Verify the Matrix client logged in successfully before initCrypto runs — check the login step's error
- Unwrap the returned error to see which argument cryptohelper rejected
- Never reuse a crypto DB across passphrases; if you change the passphrase, archive the old crypto DB
Example fix
# before crypto_passphrase: " " # whitespace-only passes the != "" check # after crypto_passphrase: "a-long-random-secret"
Defensive patterns
Strategy: validation
Validate before calling
// before starting the channel
if strings.TrimSpace(cfg.Matrix.CryptoPassphrase) == "" {
return errors.New("matrix crypto_passphrase must be a non-empty secret")
}
if client == nil {
return errors.New("matrix client must be constructed and logged in before crypto init")
} Try / catch
if err := matrixCh.Start(ctx); err != nil {
if strings.Contains(err.Error(), "create crypto helper") {
// argument rejection: fix config (passphrase) or client wiring, do not retry
return fmt.Errorf("crypto helper misconfigured: %w", err)
}
} Prevention
- Trim and validate the passphrase at config load, not deep in channel startup
- Persist the device_id after first login so crypto init is deterministic
- Alert on startup failures containing 'create crypto helper' — they are always config defects
When it happens
Trigger: Configuring matrix crypto with a passphrase of only spaces (passes the != "" guard but yields an empty/invalid pickle key after conversion); the Matrix client being nil because earlier construction/login steps failed silently; passing a nil wrappedDB after a dbutil failure path was ignored.
Common situations: YAML/env config with MATRIX_CRYPTO_PASSPHRASE=' ' from templating; pipeline variables injecting empty strings that become whitespace; refactors that construct MatrixChannel before client login completes.
Related errors
- execute %s: %w
- init crypto helper: %w
- wrap database: %w
- get device ID via whoami: %w
- no media store available: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/14ce58f4f72a2cb3.
Report an issue: GitHub.