wavetermdev/waveterm · error

no vdom context block id

Error message

no vdom context block id

What it means

SendAsyncInitiation requires the client to already know its vdom context block id (c.VDomContextBlockId), which is set after CreateVDomContext succeeds. If it is empty, the client has no frontend route to target, so the call refuses to send VDomAsyncInitiationCommand. It is an ordering/state guard, not a transport failure.

Source

Thrown at pkg/waveapp/waveapp.go:231

	}, &wshrpc.RpcOpts{Timeout: 5000})
	if err != nil {
		return fmt.Errorf("error waiting for vdom context route: %v", err)
	}
	if !gotRoute {
		return fmt.Errorf("vdom context route could not be established")
	}
	wshclient.EventSubCommand(c.RpcClient, wps.SubscriptionRequest{Event: wps.Event_BlockClose, Scopes: []string{
		blockORef.String(),
	}}, nil)
	c.RpcClient.EventListener.On("blockclose", func(event *wps.WaveEvent) {
		c.doShutdown("got blockclose event")
	})
	return nil
}

func (c *Client) SendAsyncInitiation() error {
	if c.VDomContextBlockId == "" {
		return fmt.Errorf("no vdom context block id")
	}
	if c.GetIsDone() {
		return fmt.Errorf("client is done")
	}
	return wshclient.VDomAsyncInitiationCommand(
		c.RpcClient,
		vdom.MakeAsyncInitiationRequest(c.RpcContext.BlockId),
		&wshrpc.RpcOpts{Route: wshutil.MakeFeBlockRouteId(c.VDomContextBlockId)},
	)
}

func (c *Client) SetAtomVals(m map[string]any) {
	for k, v := range m {
		c.Root.SetAtomVal(k, v, true)
	}
}

func (c *Client) SetAtomVal(name string, val any) {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Call CreateVDomContext (and check its error) before SendAsyncInitiation.
  2. Wait for app initialization to complete (e.g. after Connect/NotifyInit) before sending async initiation.
  3. If racing with startup, poll until c.VDomContextBlockId is set or use a ready channel/signal.
  4. Do not construct Client manually; use the exported Connect flow.
  5. Log client state (VDomContextBlockId, RouteId) when this error fires to see which init step was skipped.

Example fix

// before
client.SendAsyncInitiation() // may run before CreateVDomContext
// after
if err := client.CreateVDomContext(ctx); err != nil { log.Fatal(err) }
if err := client.SendAsyncInitiation(); err != nil { log.Fatal(err) }
Defensive patterns

Strategy: validation

Validate before calling

if client.VDomContextBlockId == "" {
    return fmt.Errorf("call CreateVDomContext before SendAsyncInitiation")
}

Type guard

func readyForAsyncInitiation(c *waveapp.Client) bool {
    return c.VDomContextBlockId != "" && !c.GetIsDone()
}

Try / catch

if err := client.SendAsyncInitiation(); err != nil {
    if strings.Contains(err.Error(), "no vdom context block id") {
        // init order bug: run CreateVDomContext first
    }
    return err
}

Prevention

When it happens

Trigger: Calling SendAsyncInitiation before CreateVDomContext completed, after CreateVDomContext failed, or on a Client constructed without going through the normal Connect+CreateVDomContext flow.

Common situations: Calling SendAsyncInitiation from a goroutine that races app startup; ignoring the error from CreateVDomContext and proceeding; manually building a Client struct in tests without a context.

Related errors


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