IceWhaleTech/CasaOS · critical
sqlite connect error
Error message
sqlite connect error
What it means
A panic raised by GetDb() in pkg/sqlite/db.go when gorm.Open(sqlite.Open(...)) fails to open the SQLite database file at dbPath/casaOS.db. Unlike the HTTP errors, this is a process-killing panic, not a returned error: any caller that triggers the first initialization on a bad path crashes the whole CasaOS binary. Typical root causes are an unwritable/missing directory, a corrupted database file, or file locking conflicts from concurrent access (SQLite allows one writer).
Source
Thrown at pkg/sqlite/db.go:35
"github.com/IceWhaleTech/CasaOS/pkg/utils/file"
model2 "github.com/IceWhaleTech/CasaOS/service/model"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
)
var gdb *gorm.DB
func GetDb(dbPath string) *gorm.DB {
if gdb != nil {
return gdb
}
// Refer https://github.com/go-sql-driver/mysql#dsn-data-source-name
// dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", m.User, m.PWD, m.IP, m.Port, m.DBName)
// db, err := gorm.Open(mysql2.Open(dsn), &gorm.Config{})
file.IsNotExistMkDir(dbPath)
db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
if err != nil {
panic("sqlite connect error")
}
c, _ := db.DB()
c.SetMaxIdleConns(10)
c.SetMaxOpenConns(1)
c.SetConnMaxIdleTime(time.Second * 1000)
gdb = db
err = db.AutoMigrate(&model2.AppNotify{}, model2.SharesDBModel{}, model2.ConnectionsDBModel{}, model2.PeerDriveDBModel{})
if err != nil {
fmt.Println(err)
}
db.Exec("DROP TABLE IF EXISTS o_application")
db.Exec("DROP TABLE IF EXISTS o_friend")
db.Exec("DROP TABLE IF EXISTS o_person_download")
db.Exec("DROP TABLE IF EXISTS o_person_down_record")
return dbView on GitHub (pinned to 0d3b2f444e)
Solutions
- Check permissions/ownership of dbPath (ls -ld) and chown it to the user running CasaOS; ensure it is writable.
- Check disk space (df -h) and free space so SQLite can write its journal/WAL.
- If another instance holds the file, stop it (only one CasaOS may own casaOS.db), or move the stale lock aside.
- If the db is corrupt, back it up and delete casaOS.db so AutoMigrate rebuilds a fresh schema (accepting loss of notify/shares/connections tables).
- Longer term, replace panic with a returned error or a logged fatal that includes the gorm err so the cause is visible.
Example fix
// before
db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
if err != nil {
panic("sqlite connect error")
}
// after
db, err := gorm.Open(sqlite.Open(dbPath+"/casaOS.db"), &gorm.Config{})
if err != nil {
logger.Error("sqlite connect error", zap.String("path", dbPath), zap.Error(err))
panic(fmt.Sprintf("sqlite connect error: %v", err))
} Defensive patterns
Strategy: validation
Validate before calling
// before first GetDb() call
info, err := os.Stat(dbPath)
if err != nil || !info.IsDir() {
return fmt.Errorf("db path %s missing or not a directory", dbPath)
}
if err := unix.Access(dbPath, unix.W_OK); err != nil {
return fmt.Errorf("db path %s not writable", dbPath)
}
disk := syscall.Statfs_t{}
if err := syscall.Statfs(dbPath, &disk); err == nil && disk.Bavail*uint64(disk.Bsize) < 10<<20 {
return fmt.Errorf("less than 10MB free for sqlite db")
} Try / catch
// GetDb panics, so guard at process level if you embed CasaOS code:
func safeDbInit(path string) (db *gorm.DB, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("sqlite init panic: %v", r)
}
}()
return sqlite.GetDb(path), nil
} Prevention
- Validate the data directory exists, is writable, and has free space before first use.
- Run exactly one CasaOS instance per casaOS.db — SQLite allows a single writer (the code even sets MaxOpenConns(1)).
- Keep the db on a local filesystem with POSIX locks; avoid NFS/FUSE-only mounts.
- Back up casaOS.db before upgrades so corruption can be recovered by restore rather than rebuild.
When it happens
Trigger: (1) dbPath directory has wrong ownership/permissions (common when the data dir was moved or restored), (2) casaOS.db is corrupt from an unclean power-off (no WAL checkpoint completed), (3) another CasaOS instance or process holds the file lock, (4) disk full so SQLite cannot create its journal, (5) dbPath on a filesystem (some NFS/FUSE mounts) without working POSIX locks.
Common situations: First start after OS reinstall with an old /DATA partition preserved; SD-card wear causing a truncated db file; running two CasaOS versions simultaneously during an upgrade; Docker bind-mount with read-only volume for /var/lib/casaos; migration tool copying the db with wrong uid.
Related errors
- access using relative path is not allowed
- mount failed
- unmount failed
- create config failed
- get config failed
AI-assisted analysis of IceWhaleTech/CasaOS@0d3b2f444e (2026-08-15).
Data as JSON: /api/errors/ca0cad6e7e889637.
Report an issue: GitHub.