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
- Call CreateVDomContext (and check its error) before SendAsyncInitiation.
- Wait for app initialization to complete (e.g. after Connect/NotifyInit) before sending async initiation.
- If racing with startup, poll until c.VDomContextBlockId is set or use a ready channel/signal.
- Do not construct Client manually; use the exported Connect flow.
- 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
- Always call CreateVDomContext (checking its error) before SendAsyncInitiation.
- Use a readiness signal/channel instead of guessing init order.
- Never construct waveapp.Client manually; use Connect.
- Log VDomContextBlockId and RouteId at startup to trace init state.
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
- client is done
- no job attached to controller
- error getting block: %w
- no shell input chan
- Layout model not found
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/654ca7b3b8fcff49.
Report an issue: GitHub.