wavetermdev/waveterm · error

no source in routeannounce

Error message

no source in routeannounce

What it means

RouteAnnounceCommand is the control-protocol handler for 'routeannounce' messages arriving on a router's control channel. The originating source route id is read from the RPC context via GetRpcSourceFromContext; announce handling needs to know which link announced the route, so if the context carries no source, the command is rejected. This indicates the announce was dispatched without proper routing context rather than a normal runtime condition.

Source

Thrown at pkg/wshutil/wshrouter_controlimpl.go:28

	"github.com/wavetermdev/waveterm/pkg/baseds"
	"github.com/wavetermdev/waveterm/pkg/util/shellutil"
	"github.com/wavetermdev/waveterm/pkg/util/utilfn"
	"github.com/wavetermdev/waveterm/pkg/waveobj"
	"github.com/wavetermdev/waveterm/pkg/wshrpc"
	"github.com/wavetermdev/waveterm/pkg/wstore"
)

type WshRouterControlImpl struct {
	Router *WshRouter
}

func (impl *WshRouterControlImpl) WshServerImpl() {}

func (impl *WshRouterControlImpl) RouteAnnounceCommand(ctx context.Context) error {
	source := GetRpcSourceFromContext(ctx)
	if source == "" {
		return fmt.Errorf("no source in routeannounce")
	}
	handler := GetRpcResponseHandlerFromContext(ctx)
	if handler == nil {
		return fmt.Errorf("no response handler in context")
	}
	linkId := handler.GetIngressLinkId()
	if linkId == baseds.NoLinkId {
		return fmt.Errorf("no ingress link found")
	}
	return impl.Router.bindRoute(linkId, source, false)
}

func (impl *WshRouterControlImpl) RouteUnannounceCommand(ctx context.Context) error {
	source := GetRpcSourceFromContext(ctx)
	if source == "" {
		return fmt.Errorf("no source in routeunannounce")
	}
	handler := GetRpcResponseHandlerFromContext(ctx)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Ensure the sending side has its source route bound (bindRouteLocally with isSourceRoute=true) before emitting routeannounce, so the context carries the source
  2. Send routeannounce through the normal WshRouter/WshClient control path rather than constructing the RPC context manually
  3. Check that GetRpcResponseHandlerFromContext / ingress link setup ran for the connection before the announce is dispatched

Example fix

// before
ctx := context.Background()
err := wshclient.RouteAnnounceCommand(ctx, client) // no source in ctx
// after
ctx = context.WithValue(context.Background(), RpcSourceKey{}, sourceRouteId)
err = wshclient.RouteAnnounceCommand(ctx, client)
Defensive patterns

Strategy: try-catch

Validate before calling

source := wshutil.GetRpcSourceFromContext(ctx)
if source == "" {
    return fmt.Errorf("cannot announce: no source route bound")
}
err := wshclient.RouteAnnounceCommand(ctx, client)

Type guard

func hasRpcSource(ctx context.Context) bool {
    return wshutil.GetRpcSourceFromContext(ctx) != ""
}
if !hasRpcSource(ctx) { return }

Try / catch

err := wshclient.RouteAnnounceCommand(ctx, client)
if err != nil && strings.Contains(err.Error(), "no source in routeannounce") {
    // the ingress link's source route was never bound; bind it before announcing
}

Prevention

When it happens

Trigger: A routeannounce control message processed through a code path that did not set the RPC source in the context (missing source-route binding on the ingress link, or a hand-built context without the source annotation).

Common situations: Sending raw routeannounce control messages over a connection without the router having bound the sender's source route; custom/protocol-level clients speaking wsh control protocol without setting up context metadata; a router regression where ingress link id / source context is lost before the control impl runs.

Related errors


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