{"record":{"id":"2d9d185a468d088e","repo":"wavetermdev/waveterm","slug":"error-updating-client-w-2d9d18","errorCode":null,"errorMessage":"error updating client: %w","messagePattern":"error updating client: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wcore/window.go","lineNumber":125,"sourceCode":"\t\tIsNew:       true,\n\t\tPos: waveobj.Point{\n\t\t\tX: 0,\n\t\t\tY: 0,\n\t\t},\n\t\tWinSize: *winSize,\n\t}\n\terr := wstore.DBInsert(ctx, window)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error inserting window: %w\", err)\n\t}\n\tclient, err := GetClientData(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting client: %w\", err)\n\t}\n\tclient.WindowIds = append(client.WindowIds, windowId)\n\terr = wstore.DBUpdate(ctx, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error updating client: %w\", err)\n\t}\n\treturn GetWindow(ctx, windowId)\n}\n\n// CloseWindow closes a window and deletes its workspace if it is empty and not named.\n// If fromElectron is true, it does not send an event to Electron.\nfunc CloseWindow(ctx context.Context, windowId string, fromElectron bool) error {\n\tlog.Printf(\"CloseWindow %s\\n\", windowId)\n\twindow, err := GetWindow(ctx, windowId)\n\tif err == nil {\n\t\tlog.Printf(\"got window %s\\n\", windowId)\n\t\tdeleted, _, err := DeleteWorkspace(ctx, window.WorkspaceId, false)\n\t\tif err != nil {\n\t\t\tlog.Printf(\"error deleting workspace: %v\\n\", err)\n\t\t}\n\t\tif deleted {\n\t\t\tlog.Printf(\"deleted workspace %s\\n\", window.WorkspaceId)\n\t\t}","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wcore/window.go#L107-L143","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the wrapped %w error for the write failure root cause","Verify no second waveterm instance holds a lock on the DB","Clean up the orphaned window row (DBDelete) since client registration failed","Retry CreateWindow once the DB is writable"],"exampleFix":"// before\nerr = wstore.DBUpdate(ctx, client)\nif err != nil {\n\treturn nil, fmt.Errorf(\"error updating client: %w\", err)\n}\n// after\nif err := wstore.DBUpdate(ctx, client); err != nil {\n\t_ = wstore.DBDelete(ctx, waveobj.OType_Window, windowId) // roll back orphaned window\n\treturn nil, fmt.Errorf(\"error updating client: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"if _, err := wcore.GetClientData(ctx); err != nil {\n\treturn fmt.Errorf(\"client record unreadable before window creation: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"win, err := wcore.CreateWindow(ctx, winSize, workspaceId)\nif err != nil && strings.Contains(err.Error(), \"error updating client\") {\n\t// window inserted but not registered — clean up orphan\n\tlog.Printf(\"partial window creation: %v\", err)\n\treturn err\n}","preventionTips":["Serialize window creation (mutex) to avoid racing on the Client singleton","Run a single waveterm process per state directory","Reconcile client.WindowIds against actual windows on startup"],"tags":["database","wave-terminal","client-data","consistency"],"backgroundTag":"database-update-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}