wavetermdev/waveterm · critical
error getting mainserver: %w
Error message
error getting mainserver: %w
What it means
InitMainServer loads the MainServer singleton from the local wstore database. If DBGetSingleton returns any error other than ErrNotFound (which means 'create a new one'), this error wraps it and aborts startup. It indicates the main server record could not be read from the underlying store.
Source
Thrown at pkg/wcore/wcore.go:178
}
}()
}
func InitMainServer() error {
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn()
mainServer, err := wstore.DBGetSingleton[*waveobj.MainServer](ctx)
if err == wstore.ErrNotFound {
mainServer = &waveobj.MainServer{
OID: uuid.NewString(),
}
err = wstore.DBInsert(ctx, mainServer)
if err != nil {
return fmt.Errorf("error inserting mainserver: %w", err)
}
} else if err != nil {
return fmt.Errorf("error getting mainserver: %w", err)
}
needsUpdate := false
if mainServer.JwtPrivateKey == "" || mainServer.JwtPublicKey == "" {
keyPair, err := wavejwt.GenerateKeyPair()
if err != nil {
return fmt.Errorf("error generating jwt keypair: %w", err)
}
mainServer.JwtPrivateKey = base64.StdEncoding.EncodeToString(keyPair.PrivateKey)
mainServer.JwtPublicKey = base64.StdEncoding.EncodeToString(keyPair.PublicKey)
needsUpdate = true
}
if needsUpdate {
err = wstore.DBUpdate(ctx, mainServer)
if err != nil {
return fmt.Errorf("error updating mainserver: %w", err)
}View on GitHub (pinned to a4447c1563)
Solutions
- Check the wrapped cause (`%w` chain) printed in logs for a SQLite 'database is locked'/'disk I/O error' and fix the underlying storage issue
- Verify file permissions on the Wave config/db directory (~/.waveterm) and that no other Wave process is running
- Back up and remove/rename the wave.db database so a fresh singleton is created on next start (loses stored server state)
- Ensure the app version's DB schema matches the existing DB; run the app's migration path instead of downgrading
Example fix
// before (diagnose)
err := wcore.InitMainServer()
log.Fatal(err)
// after
if err := wcore.InitMainServer(); err != nil {
log.Printf("init failed: %v", errors.Unwrap(err)) // see real DB cause
os.Exit(1)
} Defensive patterns
Strategy: try-catch
Validate before calling
// before startup
if _, err := os.Stat(dbPath); err != nil {
log.Printf("db missing, fresh start expected: %v", err)
}
if err := checkWritableDir(dbDir); err != nil {
log.Fatalf("db dir not writable: %v", err)
} Type guard
func isDBLockedErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "database is locked")
} Try / catch
if err := wcore.InitMainServer(); err != nil {
if isDBLockedErr(err) {
time.Sleep(500 * time.Millisecond)
return wcore.InitMainServer() // retry once
}
log.Fatalf("mainserver init: %v", err)
} Prevention
- Ensure only one Wave instance runs against a given wave.db
- Keep the DB directory writable and with adequate disk space
- Never run the app with mixed users (sudo vs normal) on the same DB
- Monitor the wrapped cause via errors.Unwrap to distinguish lock vs corruption
When it happens
Trigger: Calling wstore.DBGetSingleton[*waveobj.MainServer](ctx) inside InitMainServer returns a non-ErrNotFound error — e.g. the SQLite wave.db file is corrupted, locked by another process, unreadable due to file permissions, or the 5-second context times out mid-query.
Common situations: Corrupt or partially-migrated wave database after a crash or version upgrade; database file owned by another user after running with sudo; disk full; two Wave instances contending for the same DB lock.
Related errors
- opening db: %w
- error getting client: %v
- failed to create job in database: %w
- error updating client: %w
- static files not available before app initialization; use Ap
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/44185b7daedc47f0.
Report an issue: GitHub.