sipeed/picoclaw · critical
open whatsapp store: %w
Error message
open whatsapp store: %w
What it means
Returned by WhatsAppNativeChannel.Start when sql.Open(sqliteDriver, connStr) fails for the session database 'file:<storePath>/store.db?_foreign_keys=on'. Unlike most sql drivers, open errors here mean the driver name is not registered or the DSN is rejected immediately - sql.Open itself does not touch the file. The %w preserves the database/sql error.
Source
Thrown at pkg/channels/whatsapp_native/whatsapp_native.go:105
// Reset lifecycle state from any previous Stop() so a restarted channel
// behaves correctly. Use reconnectMu to be consistent with eventHandler
// and Stop() which coordinate under the same lock.
c.reconnectMu.Lock()
c.stopping.Store(false)
c.reconnecting = false
c.reconnectMu.Unlock()
if err := os.MkdirAll(c.storePath, 0o700); err != nil {
return fmt.Errorf("create session store dir: %w", err)
}
dbPath := filepath.Join(c.storePath, whatsappDBName)
connStr := "file:" + dbPath + "?_foreign_keys=on"
db, err := sql.Open(sqliteDriver, connStr)
if err != nil {
return fmt.Errorf("open whatsapp store: %w", err)
}
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
if _, err = db.ExecContext(ctx, "PRAGMA foreign_keys = ON"); err != nil {
_ = db.Close()
return fmt.Errorf("enable foreign keys: %w", err)
}
waLogger := waLog.Stdout("WhatsApp", "WARN", true)
container := sqlstore.NewWithDB(db, sqliteDriver, waLogger)
if err = container.Upgrade(ctx); err != nil {
_ = db.Close()
return fmt.Errorf("open whatsapp store: %w", err)
}
deviceStore, err := container.GetFirstDevice(ctx)
if err != nil {
_ = container.Close()View on GitHub (pinned to 49183d7e8d)
Solutions
- Rebuild with the same build tags used for the sqlite driver import (whatsapp_native tag set) so the driver registers.
- Confirm CGO settings match the chosen sqlite driver (CGO_ENABLED=1 for mattn/go-sqlite3, or use the pure-Go driver).
- Print/inspect the effective storePath to rule out DSN-breaking characters.
- Check sqliteDriver constant in the package matches the driver name registered by the imported library.
Defensive patterns
Strategy: validation
Validate before calling
// Verify the sqlite driver is linked into this build before Start:
var found bool
for _, d := range sql.Drivers() {
if d == "sqlite" { found = true }
}
if !found {
return errors.New("sqlite driver not compiled in; rebuild with the required build tags")
} Try / catch
if err := ch.Start(ctx); err != nil {
if strings.Contains(err.Error(), "open whatsapp store") {
// distinguish sql.Open failure (driver/DSN) from later upgrade failure via unwrap chain
}
} Prevention
- Build with a consistent set of build tags so driver import and whatsapp_native code ship together.
- Pin CGO_ENABLED explicitly in build scripts when using a CGO sqlite driver.
- Add a startup self-check listing sql.Drivers() in debug logs.
When it happens
Trigger: Start(ctx) builds the DSN from storePath and calls sql.Open; failure occurs when the sqlite driver (CGO or pure-Go, depending on build tags) was not linked into the binary, or the DSN is malformed for the registered driver (e.g. unsupported '_foreign_keys' query parameter).
Common situations: Building with a driver variant that registers a different driver name (e.g. 'sqlite3' vs 'sqlite'); CGO disabled causing the CGO sqlite driver to be excluded; a build-tag mismatch between the driver import and whatsapp_native code; storePath containing characters the DSN parser rejects.
Related errors
- failed to connect to WhatsApp bridge: %w
- create session store dir: %w
- enable foreign keys: %w
- get device store: %w
- whatsapp native not compiled in; build with -tags whatsapp_n
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/7cbbdcc986452d0e.
Report an issue: GitHub.