wavetermdev/waveterm · error
no route for %q
Error message
no route for %q
What it means
WshRouter routes RPCs and events by routeId. noRouteErr produces this error when a message arrives (or is sent) for a routeId that has no registered route and no default route is configured; an empty routeId yields the plainer "no default route" error. It indicates the wsh message could not be delivered to any handler.
Source
Thrown at pkg/wshutil/wshrouter.go:196
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)
if err != nil {
// nothing to doView on GitHub (pinned to a4447c1563)
Solutions
- Verify the routeId against the wshrpc.RouteId_* constants and fix typos.
- Ensure the remote side has registered the route before sending — wait for connection/route-ready (e.g. retry after registering controllers), or use the default controller route for general commands.
- Check that the target block/route still exists (the block may have been closed, unregistering its route); reacquire a valid routeId.
- If routing to your own endpoint, call router.RegisterRoute(routeId, processor) before sending traffic to it.
Example fix
// before: guessing a route id
client.SendRpcRequest(ctx, "routeservice", req) // no route for "routeservice"
// after: use the declared constant / register first
err := client.SendRpcRequest(ctx, wshrpc.RouteId_Controller, req)
// or, for a custom endpoint:
router.RegisterRoute("routeservice", myProcessor)
err := client.SendRpcRequest(ctx, "routeservice", req) Defensive patterns
Strategy: retry
Validate before calling
// Confirm the route is registered before sending:
if !routerHasRoute(routeId) {
return fmt.Errorf("route %s not yet registered; wait for connection", routeId)
} Try / catch
err := client.SendRpcRequest(ctx, routeId, req)
if err != nil && (strings.Contains(err.Error(), "no route for") || strings.Contains(err.Error(), "no default route")) {
// brief backoff then re-resolve the route and retry once
time.Sleep(250 * time.Millisecond)
routeId = resolveRoute()
return client.SendRpcRequest(ctx, routeId, req)
} Prevention
- Use wshrpc.RouteId_* constants instead of hand-written route strings.
- Wait for connection/route-ready signals before issuing the first RPC.
- Handle closed blocks/routes: re-resolve routeIds instead of caching them indefinitely.
- Register custom routes (RegisterRoute) before sending traffic to them.
When it happens
Trigger: Sending an RPC/event with SendRpcRequest/SendEvent to a routeId that was never registered (RegisterRoute) or was already unregistered (UnregisterRoute); specifying a route before the remote side finished setting up its routes; a typo in a RouteId.
Common situations: Calling a server command before the websocket/controller connection is established so the route is not yet registered; a remote block/terminal closed so its route disappeared; hand-writing route strings instead of using wshrpc.RouteId_* constants; race between route registration and the first RPC after connection.
Related errors
- command %q not implemented
- command %q not found
- error re-marshalling command data: %w
- command not implemented %q
- command %q invalid multi arg payload
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/5c8e775738200be5.
Report an issue: GitHub.