{"record":{"id":"8c3d22fbaa0ab0f8","repo":"sipeed/picoclaw","slug":"create-session-store-dir-w","errorCode":null,"errorMessage":"create session store dir: %w","messagePattern":"create session store dir: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"pkg/channels/whatsapp_native/whatsapp_native.go","lineNumber":97,"sourceCode":"\t\tconfig:      cfg,\n\t\tstorePath:   storePath,\n\t}\n\treturn c, nil\n}\n\nfunc (c *WhatsAppNativeChannel) Start(ctx context.Context) error {\n\tlogger.InfoCF(\"whatsapp\", \"Starting WhatsApp native channel (whatsmeow)\", map[string]any{\"store\": c.storePath})\n\n\t// Reset lifecycle state from any previous Stop() so a restarted channel\n\t// behaves correctly.  Use reconnectMu to be consistent with eventHandler\n\t// and Stop() which coordinate under the same lock.\n\tc.reconnectMu.Lock()\n\tc.stopping.Store(false)\n\tc.reconnecting = false\n\tc.reconnectMu.Unlock()\n\n\tif err := os.MkdirAll(c.storePath, 0o700); err != nil {\n\t\treturn fmt.Errorf(\"create session store dir: %w\", err)\n\t}\n\n\tdbPath := filepath.Join(c.storePath, whatsappDBName)\n\tconnStr := \"file:\" + dbPath + \"?_foreign_keys=on\"\n\n\tdb, err := sql.Open(sqliteDriver, connStr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open whatsapp store: %w\", err)\n\t}\n\tdb.SetMaxOpenConns(1)\n\tdb.SetMaxIdleConns(1)\n\tif _, err = db.ExecContext(ctx, \"PRAGMA foreign_keys = ON\"); err != nil {\n\t\t_ = db.Close()\n\t\treturn fmt.Errorf(\"enable foreign keys: %w\", err)\n\t}\n\n\twaLogger := waLog.Stdout(\"WhatsApp\", \"WARN\", true)\n\tcontainer := sqlstore.NewWithDB(db, sqliteDriver, waLogger)","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/whatsapp_native/whatsapp_native.go#L79-L115","documentation":"Returned by WhatsAppNativeChannel.Start when os.MkdirAll fails to create the whatsmeow session store directory (c.storePath) with mode 0700. The %w chain keeps the OS error (e.g. permission denied, path component is a file, read-only filesystem). Start aborts before opening the sqlite session database.","triggerScenarios":"Start(ctx) with storePath whose parent lacks write permission, a path where an existing regular file occupies a needed directory component, a read-only volume, or SELinux/AppArmor denial.","commonSituations":"Running the binary as an unprivileged user against /var/lib/... or another root-owned path; container with a read-only or unmounted volume at the store path; store path misconfigured to something like /proc/... or a path containing a stray file; macOS/linux permission mismatch after moving the data dir.","solutions":["Check the store path in channel config and ensure every parent directory exists and is writable by the service user.","Create the directory manually with correct ownership: install -d -o <user> -m 700 <storePath>.","If running in Docker, confirm the volume is mounted rw at the configured path.","Look for a regular file shadowing a directory component (e.g. a file named like the dir) and remove/rename it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"info, err := os.Stat(storePath)\nswitch {\ncase err == nil && !info.IsDir():\n    return fmt.Errorf(\"store path %s exists and is not a directory\", storePath)\ncase os.IsNotExist(err):\n    if err := os.MkdirAll(storePath, 0o700); err != nil { return err }\ncase err != nil:\n    return err\n}","typeGuard":null,"tryCatchPattern":"if err := ch.Start(ctx); err != nil {\n    if errors.Is(err, fs.ErrPermission) || strings.Contains(err.Error(), \"create session store dir\") {\n        // fix directory ownership/permissions, then retry Start\n    }\n}","preventionTips":["Create and chown the store directory as part of deployment (systemd StateDirectory, Docker volume, etc.).","Smoke-test storePath writability with a temp file before enabling the channel.","Never run the service once as root and then as an unprivileged user against the same store."],"tags":["whatsapp","whatsmeow","filesystem","permissions","startup"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}