wavetermdev/waveterm · error

update wavobj is nil

Error message

update wavobj is nil

What it means

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.

Source

Thrown at pkg/service/objectservice/objectservice.go:147

	err = wstore.UpdateObjectMeta(ctx, *oref, meta, false)
	if err != nil {
		return nil, fmt.Errorf("error updating %q meta: %w", orefStr, err)
	}
	return waveobj.ContextGetUpdatesRtn(ctx), nil
}

func (svc *ObjectService) UpdateObject_Meta() tsgenmeta.MethodMeta {
	return tsgenmeta.MethodMeta{
		ArgNames: []string{"uiContext", "waveObj", "returnUpdates"},
	}
}

func (svc *ObjectService) UpdateObject(uiContext waveobj.UIContext, waveObj waveobj.WaveObj, returnUpdates bool) (waveobj.UpdatesRtnType, error) {
	ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
	defer cancelFn()
	ctx = waveobj.ContextWithUpdates(ctx)
	if waveObj == nil {
		return nil, fmt.Errorf("update wavobj is nil")
	}
	oref := waveobj.ORefFromWaveObj(waveObj)
	found, err := wstore.DBExistsORef(ctx, *oref)
	if err != nil {
		return nil, fmt.Errorf("error getting object: %w", err)
	}
	if !found {
		return nil, fmt.Errorf("object not found: %s", oref)
	}
	err = wstore.DBUpdate(ctx, waveObj)
	if err != nil {
		return nil, fmt.Errorf("error updating object: %w", err)
	}
	if (waveObj.GetOType() == waveobj.OType_Workspace) && (waveObj.(*waveobj.Workspace).Name != "") {
		wps.Broker.Publish(wps.WaveEvent{
			Event: wps.Event_WorkspaceUpdate})
	}
	if returnUpdates {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check the object for nil before calling UpdateObject and return a meaningful error.
  2. Verify the upstream lookup succeeded and returned non-nil (confirm existence via wstore.DBExistsORef with a valid ORef).
  3. Trace where the nil originates; likely a deleted or never-created OID.
  4. If only the OID is known, fetch the object first, mutate, then update.

Example fix

// before
err := objectservice.UpdateObject(uiCtx, block, true)
// after
if block == nil {
    return fmt.Errorf("cannot update: block %q not found", oid)
}
err := objectservice.UpdateObject(uiCtx, block, true)
Defensive patterns

Strategy: validation

Validate before calling

if obj == nil {
    return fmt.Errorf("cannot update: wave object is nil")
}
return svc.UpdateObject(uiCtx, obj, true)

Type guard

func isNilWaveObj(w waveobj.WaveObj) bool {
    return w == nil || reflect.ValueOf(w).IsNil()
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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