{"record":{"id":"654ca7b3b8fcff49","repo":"wavetermdev/waveterm","slug":"no-vdom-context-block-id","errorCode":null,"errorMessage":"no vdom context block id","messagePattern":"no vdom context block id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/waveapp/waveapp.go","lineNumber":231,"sourceCode":"\t}, &wshrpc.RpcOpts{Timeout: 5000})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error waiting for vdom context route: %v\", err)\n\t}\n\tif !gotRoute {\n\t\treturn fmt.Errorf(\"vdom context route could not be established\")\n\t}\n\twshclient.EventSubCommand(c.RpcClient, wps.SubscriptionRequest{Event: wps.Event_BlockClose, Scopes: []string{\n\t\tblockORef.String(),\n\t}}, nil)\n\tc.RpcClient.EventListener.On(\"blockclose\", func(event *wps.WaveEvent) {\n\t\tc.doShutdown(\"got blockclose event\")\n\t})\n\treturn nil\n}\n\nfunc (c *Client) SendAsyncInitiation() error {\n\tif c.VDomContextBlockId == \"\" {\n\t\treturn fmt.Errorf(\"no vdom context block id\")\n\t}\n\tif c.GetIsDone() {\n\t\treturn fmt.Errorf(\"client is done\")\n\t}\n\treturn wshclient.VDomAsyncInitiationCommand(\n\t\tc.RpcClient,\n\t\tvdom.MakeAsyncInitiationRequest(c.RpcContext.BlockId),\n\t\t&wshrpc.RpcOpts{Route: wshutil.MakeFeBlockRouteId(c.VDomContextBlockId)},\n\t)\n}\n\nfunc (c *Client) SetAtomVals(m map[string]any) {\n\tfor k, v := range m {\n\t\tc.Root.SetAtomVal(k, v, true)\n\t}\n}\n\nfunc (c *Client) SetAtomVal(name string, val any) {","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/waveapp/waveapp.go#L213-L249","documentation":"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.","triggerScenarios":"Calling SendAsyncInitiation before CreateVDomContext completed, after CreateVDomContext failed, or on a Client constructed without going through the normal Connect+CreateVDomContext flow.","commonSituations":"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.","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."],"exampleFix":"// before\nclient.SendAsyncInitiation() // may run before CreateVDomContext\n// after\nif err := client.CreateVDomContext(ctx); err != nil { log.Fatal(err) }\nif err := client.SendAsyncInitiation(); err != nil { log.Fatal(err) }","handlingStrategy":"validation","validationCode":"if client.VDomContextBlockId == \"\" {\n    return fmt.Errorf(\"call CreateVDomContext before SendAsyncInitiation\")\n}","typeGuard":"func readyForAsyncInitiation(c *waveapp.Client) bool {\n    return c.VDomContextBlockId != \"\" && !c.GetIsDone()\n}","tryCatchPattern":"if err := client.SendAsyncInitiation(); err != nil {\n    if strings.Contains(err.Error(), \"no vdom context block id\") {\n        // init order bug: run CreateVDomContext first\n    }\n    return err\n}","preventionTips":["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."],"tags":["vdom","initialization-order","state","lifecycle"],"backgroundTag":"client-not-initialized","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}