{"record":{"id":"c0d376978d9a8108","repo":"wavetermdev/waveterm","slug":"no-default-route","errorCode":null,"errorMessage":"no default route","messagePattern":"no default route","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshrouter.go","lineNumber":194,"sourceCode":"\treturn router.controlRpc\n}\n\nfunc (router *WshRouter) SetAsRootRouter() {\n\trouter.lock.Lock()\n\tdefer router.lock.Unlock()\n\trouter.isRootRouter = true\n\n\t// also bind $control:root to the control RPC\n\tlinkId := router.routeMap[ControlRoute]\n\tif linkId != baseds.NoLinkId {\n\t\trouter.routeMap[ControlRootRoute] = linkId\n\t\tlog.Printf(\"wshrouter registered control:root route linkid=%d\", linkId)\n\t}\n}\n\nfunc noRouteErr(routeId string) error {\n\tif routeId == \"\" {\n\t\treturn errors.New(\"no default route\")\n\t}\n\treturn fmt.Errorf(\"no route for %q\", routeId)\n}\n\nfunc (router *WshRouter) SendEvent(routeId string, event wps.WaveEvent) {\n\tdefer func() {\n\t\tpanichandler.PanicHandler(\"WshRouter.SendEvent\", recover())\n\t}()\n\tlm := router.getLinkForRoute(routeId)\n\tif lm == nil {\n\t\treturn\n\t}\n\tmsg := RpcMessage{\n\t\tCommand: wshrpc.Command_EventRecv,\n\t\tRoute:   routeId,\n\t\tData:    event,\n\t}\n\tmsgBytes, err := json.Marshal(msg)","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshrouter.go#L176-L212","documentation":"WshRouter routes wsh commands and events to registered route IDs. When SendEvent/SendRpc is called with an empty routeId and no default route is registered, the router has no destination to forward to, so it throws \"no default route\". This is the empty-routeId branch of noRouteErr; a non-empty unknown route yields \"no route for %q\" instead.","triggerScenarios":"Calling WshRouter.SendEvent or an RPC send with routeId==\"\" before/without registering a default route via the control:root route registration path (e.g. router not fully initialized, connection torn down so the default route registration never happened).","commonSituations":"Sending events during startup before the router's control:root route is registered; using an empty route variable from config; calling after the connection was closed and routes were unregistered.","solutions":["Initialize the router/connection fully before sending; ensure the control:root default route registration completes first.","Pass a valid non-empty routeId (e.g. wshutil.MakeConnectionRouteId(...)) instead of an empty string.","Check connection state before sending; skip sends when the router has no active connection.","Log the routeId at the call site to catch empty values early.","Wrap sends in a retry/queue that defers until the default route is registered."],"exampleFix":"// before\nrouter.SendEvent(\"\", wps.WaveEvent{Event: \"app:update\"})\n// after\nif routeId == \"\" {\n    routeId = wshutil.MakeConnectionRouteId(connName)\n}\nrouter.SendEvent(routeId, wps.WaveEvent{Event: \"app:update\"})","handlingStrategy":"validation","validationCode":"if routeId == \"\" {\n    return fmt.Errorf(\"cannot send: routeId is empty, default route not registered yet\")\n}","typeGuard":null,"tryCatchPattern":"data, err := router.SendRpc(routeId, ...)\nif err != nil && strings.Contains(err.Error(), \"no route\") {\n    // defer/queue until default route registered\n}","preventionTips":["Never pass a literal \"\" as routeId; derive it via MakeConnectionRouteId.","Await the connection/router-ready signal before sending.","Centralize sends in a helper that validates routeId first.","Log route registration order in startup code."],"tags":["go","rpc","routing"],"backgroundTag":"no-route-registered","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}