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

  1. Initialize the router/connection fully before sending; ensure the control:root default route registration completes first.
  2. Pass a valid non-empty routeId (e.g. wshutil.MakeConnectionRouteId(...)) instead of an empty string.
  3. Check connection state before sending; skip sends when the router has no active connection.
  4. Log the routeId at the call site to catch empty values early.
  5. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/c0d376978d9a8108. Report an issue: GitHub.