wavetermdev/waveterm · error
no default route
Error message
no default route
What it means
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.
Source
Thrown at pkg/wshutil/wshrouter.go:194
return router.controlRpc
}
func (router *WshRouter) SetAsRootRouter() {
router.lock.Lock()
defer router.lock.Unlock()
router.isRootRouter = true
// also bind $control:root to the control RPC
linkId := router.routeMap[ControlRoute]
if linkId != baseds.NoLinkId {
router.routeMap[ControlRootRoute] = linkId
log.Printf("wshrouter registered control:root route linkid=%d", linkId)
}
}
func noRouteErr(routeId string) error {
if routeId == "" {
return errors.New("no default route")
}
return fmt.Errorf("no route for %q", routeId)
}
func (router *WshRouter) SendEvent(routeId string, event wps.WaveEvent) {
defer func() {
panichandler.PanicHandler("WshRouter.SendEvent", recover())
}()
lm := router.getLinkForRoute(routeId)
if lm == nil {
return
}
msg := RpcMessage{
Command: wshrpc.Command_EventRecv,
Route: routeId,
Data: event,
}
msgBytes, err := json.Marshal(msg)View on GitHub (pinned to a4447c1563)
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.
Example fix
// before
router.SendEvent("", wps.WaveEvent{Event: "app:update"})
// after
if routeId == "" {
routeId = wshutil.MakeConnectionRouteId(connName)
}
router.SendEvent(routeId, wps.WaveEvent{Event: "app:update"}) Defensive patterns
Strategy: validation
Validate before calling
if routeId == "" {
return fmt.Errorf("cannot send: routeId is empty, default route not registered yet")
} Try / catch
data, err := router.SendRpc(routeId, ...)
if err != nil && strings.Contains(err.Error(), "no route") {
// defer/queue until default route registered
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- RPC error: %v
- nil wshrpc passed to wshclient
- response channel closed
- <resp.Error>
- server is no longer running, cannot send new requests
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/c0d376978d9a8108.
Report an issue: GitHub.