{"record":{"id":"86553c112bf5fd62","repo":"wavetermdev/waveterm","slug":"object-not-found-s","errorCode":null,"errorMessage":"object not found: %s","messagePattern":"object not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/objectservice/objectservice.go","lineNumber":155,"sourceCode":"\treturn tsgenmeta.MethodMeta{\n\t\tArgNames: []string{\"uiContext\", \"waveObj\", \"returnUpdates\"},\n\t}\n}\n\nfunc (svc *ObjectService) UpdateObject(uiContext waveobj.UIContext, waveObj waveobj.WaveObj, returnUpdates bool) (waveobj.UpdatesRtnType, error) {\n\tctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)\n\tdefer cancelFn()\n\tctx = waveobj.ContextWithUpdates(ctx)\n\tif waveObj == nil {\n\t\treturn nil, fmt.Errorf(\"update wavobj is nil\")\n\t}\n\toref := waveobj.ORefFromWaveObj(waveObj)\n\tfound, err := wstore.DBExistsORef(ctx, *oref)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting object: %w\", err)\n\t}\n\tif !found {\n\t\treturn nil, fmt.Errorf(\"object not found: %s\", oref)\n\t}\n\terr = wstore.DBUpdate(ctx, waveObj)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error updating object: %w\", err)\n\t}\n\tif (waveObj.GetOType() == waveobj.OType_Workspace) && (waveObj.(*waveobj.Workspace).Name != \"\") {\n\t\twps.Broker.Publish(wps.WaveEvent{\n\t\t\tEvent: wps.Event_WorkspaceUpdate})\n\t}\n\tif returnUpdates {\n\t\treturn waveobj.ContextGetUpdatesRtn(ctx), nil\n\t}\n\treturn nil, nil\n}\n","sourceCodeStart":137,"sourceCodeEnd":170,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/objectservice/objectservice.go#L137-L170","documentation":"UpdateObject checks wstore.DBExistsORef before writing; if no object with the given ORef is stored it fails with 'object not found: <oref>'. UpdateObject only updates existing objects, it never creates them.","triggerScenarios":"Calling UpdateObject with a WaveObj whose OID was never persisted, or that was deleted (closed block, removed workspace) between fetch and update; passing a hand-constructed object with an invalid OID.","commonSituations":"Frontend holds a stale reference after the block was closed elsewhere; update races with object deletion; typos or truncated OIDs from external scripts.","solutions":["Fetch the object fresh via wstore.DBGet* before updating so you know it exists.","Use the create API if the object should be created rather than updated.","Detect deletion (e.g. block closed) and skip or re-create instead of updating.","Refresh client-side references from the backend to clear stale state."],"exampleFix":"// before\nwstore.DBUpdate(ctx, staleObj)\n// after\nexisting, err := wstore.DBGetBlock(ctx, oid)\nif err != nil {\n    return fmt.Errorf(\"block %s no longer exists, skipping update\", oid)\n}\nexisting.View = staleObj.View\nwstore.DBUpdate(ctx, existing)","handlingStrategy":"validation","validationCode":"exists, err := wstore.DBExistsORef(ctx, waveobj.ORefFromWaveObj(obj))\nif err != nil || !exists {\n    return fmt.Errorf(\"object %s does not exist; cannot update\", oref)\n}","typeGuard":null,"tryCatchPattern":"if _, err := svc.UpdateObject(uiCtx, obj, true); err != nil && strings.Contains(err.Error(), \"object not found\") {\n    // handle stale reference: refresh or re-create\n}","preventionTips":["Re-fetch objects before mutating instead of caching long-lived references.","Subscribe to object-deletion events and invalidate local caches.","Use create APIs for new objects; update only known-existing ones."],"tags":["object-not-found","wstore","stale-reference","rpc"],"backgroundTag":"object-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}