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

  1. 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
  2. Verify file permissions on the Wave config/db directory (~/.waveterm) and that no other Wave process is running
  3. Back up and remove/rename the wave.db database so a fresh singleton is created on next start (loses stored server state)
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/44185b7daedc47f0. Report an issue: GitHub.