wavetermdev/waveterm · error

error updating client: %w

Error message

error updating client: %w

What it means

CreateWindow appends the new windowId to client.WindowIds and persists the Client singleton via wstore.DBUpdate; this error wraps the update failure. The window is already inserted, so failure here leaves an inconsistent state (window exists but is not registered with the client).

Source

Thrown at pkg/wcore/window.go:125

		IsNew:       true,
		Pos: waveobj.Point{
			X: 0,
			Y: 0,
		},
		WinSize: *winSize,
	}
	err := wstore.DBInsert(ctx, window)
	if err != nil {
		return nil, fmt.Errorf("error inserting window: %w", err)
	}
	client, err := GetClientData(ctx)
	if err != nil {
		return nil, fmt.Errorf("error getting client: %w", err)
	}
	client.WindowIds = append(client.WindowIds, windowId)
	err = wstore.DBUpdate(ctx, client)
	if err != nil {
		return nil, fmt.Errorf("error updating client: %w", err)
	}
	return GetWindow(ctx, windowId)
}

// CloseWindow closes a window and deletes its workspace if it is empty and not named.
// If fromElectron is true, it does not send an event to Electron.
func CloseWindow(ctx context.Context, windowId string, fromElectron bool) error {
	log.Printf("CloseWindow %s\n", windowId)
	window, err := GetWindow(ctx, windowId)
	if err == nil {
		log.Printf("got window %s\n", windowId)
		deleted, _, err := DeleteWorkspace(ctx, window.WorkspaceId, false)
		if err != nil {
			log.Printf("error deleting workspace: %v\n", err)
		}
		if deleted {
			log.Printf("deleted workspace %s\n", window.WorkspaceId)
		}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check the wrapped %w error for the write failure root cause
  2. Verify no second waveterm instance holds a lock on the DB
  3. Clean up the orphaned window row (DBDelete) since client registration failed
  4. Retry CreateWindow once the DB is writable

Example fix

// before
err = wstore.DBUpdate(ctx, client)
if err != nil {
	return nil, fmt.Errorf("error updating client: %w", err)
}
// after
if err := wstore.DBUpdate(ctx, client); err != nil {
	_ = wstore.DBDelete(ctx, waveobj.OType_Window, windowId) // roll back orphaned window
	return nil, fmt.Errorf("error updating client: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := wcore.GetClientData(ctx); err != nil {
	return fmt.Errorf("client record unreadable before window creation: %w", err)
}

Try / catch

win, err := wcore.CreateWindow(ctx, winSize, workspaceId)
if err != nil && strings.Contains(err.Error(), "error updating client") {
	// window inserted but not registered — clean up orphan
	log.Printf("partial window creation: %v", err)
	return err
}

Prevention

When it happens

Trigger: wcore.CreateWindow where DBUpdate(ctx, client) fails after a successful read — DB write error, disk full, or the client record was deleted concurrently between read and update.

Common situations: Disk-full or permission issues mid-launch; concurrent window creation from multiple clients racing on the same Client singleton row; DB locked by another waveterm process.

Related errors


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