{"record":{"id":"f7198f1eadf61518","repo":"wavetermdev/waveterm","slug":"update-wavobj-is-nil","errorCode":null,"errorMessage":"update wavobj is nil","messagePattern":"update wavobj is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/service/objectservice/objectservice.go","lineNumber":147,"sourceCode":"\terr = wstore.UpdateObjectMeta(ctx, *oref, meta, false)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error updating %q meta: %w\", orefStr, err)\n\t}\n\treturn waveobj.ContextGetUpdatesRtn(ctx), nil\n}\n\nfunc (svc *ObjectService) UpdateObject_Meta() tsgenmeta.MethodMeta {\n\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 {","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/service/objectservice/objectservice.go#L129-L165","documentation":"ObjectService.UpdateObject refuses to proceed when the waveObj parameter is nil. The method derives an ORef from the object to locate it in wstore, and a nil object cannot produce one. This is a fail-fast guard against caller programming errors.","triggerScenarios":"Calling UpdateObject(ctx, nil, true/false) - typically when a caller fetched a wave object, got nil back (failed lookup, absent object, failed unmarshal), and passed it through without checking.","commonSituations":"Frontend RPC handlers looking up a block/workspace by stale or deleted OID get nil, then call UpdateObject with it; scripts building WaveObj variants where a typed nil ended up in a non-nil interface.","solutions":["Check the object for nil before calling UpdateObject and return a meaningful error.","Verify the upstream lookup succeeded and returned non-nil (confirm existence via wstore.DBExistsORef with a valid ORef).","Trace where the nil originates; likely a deleted or never-created OID.","If only the OID is known, fetch the object first, mutate, then update."],"exampleFix":"// before\nerr := objectservice.UpdateObject(uiCtx, block, true)\n// after\nif block == nil {\n    return fmt.Errorf(\"cannot update: block %q not found\", oid)\n}\nerr := objectservice.UpdateObject(uiCtx, block, true)","handlingStrategy":"validation","validationCode":"if obj == nil {\n    return fmt.Errorf(\"cannot update: wave object is nil\")\n}\nreturn svc.UpdateObject(uiCtx, obj, true)","typeGuard":"func isNilWaveObj(w waveobj.WaveObj) bool {\n    return w == nil || reflect.ValueOf(w).IsNil()\n}","tryCatchPattern":null,"preventionTips":["Never pass a lookup result to UpdateObject without a nil check.","Return explicit errors from fetch helpers instead of bare nil.","Log OIDs at fetch time so nil origins are traceable."],"tags":["nil-pointer","validation","wstore","rpc"],"backgroundTag":"nil-object-argument","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}