sipeed/picoclaw · error

wrap database: %w

Error message

wrap database: %w

What it means

Thrown by MatrixChannel.initCrypto when dbutil.NewWithDB fails to wrap the raw *sql.DB with mautrix's dbutil layer (pkg/channels/matrix/matrix.go:363). dbutil provides the SQL dialect (the sqliteDriver constant "sqlite" doubles as the dialect label) that the mautrix crypto store uses for its queries and migrations. Failure means the dialect could not be resolved for the driver name or the *sql.DB handle is unusable, and the DB is closed before returning.

Source

Thrown at pkg/channels/matrix/matrix.go:363

	// This is equivalent to the "sqlite3-fk-wal" dialect used by cryptohelper
	pragmaStmts := []string{
		"PRAGMA foreign_keys = ON",
		"PRAGMA journal_mode = WAL",
		"PRAGMA synchronous = NORMAL",
		"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()

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Run 'go mod tidy' so maunium.net/go/mautrix, its dbutil, and modernc.org/sqlite versions are consistent
  2. Confirm sqliteDriver still matches the driver name registered by modernc.org/sqlite ("sqlite") in the linked version
  3. Inspect the wrapped error with '%w' unwrapping (errors.As/errors.Unwrap) — dbutil reports the concrete rejection reason
  4. If it persists, test the raw handle first with db.PingContext(ctx) before wrapping to isolate driver-level failure from dialect resolution
Defensive patterns

Strategy: try-catch

Try / catch

// no caller-side pre-check exists; classify at startup and fail fast with the wrapped cause
if err := matrixCh.Start(ctx); err != nil {
	if strings.Contains(err.Error(), "wrap database") {
		log.Fatalf("dbutil rejected the sqlite dialect; check mautrix/modernc versions are in lockstep: %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling dbutil.NewWithDB with a driver/dialect name the linked mautrix version does not recognize; passing a nil or already-closed *sql.DB; version skew between maunium.net/go/mautrix, its dbutil package, and modernc.org/sqlite after a partial dependency upgrade; the *sql.DB opened with a connection string the driver rejects at first use.

Common situations: Upgrading mautrix (go.mod pins maunium.net/go/mautrix v0.27.0) without regenerating go.sum (go mod tidy); swapping the SQLite driver (mattn/go-sqlite3 vs modernc.org/sqlite) so the registered driver name no longer matches the dialect string; vendoring mismatches in downstream forks of this bot.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/d4c298949b0fa37c. Report an issue: GitHub.