wavetermdev/waveterm · error
invalid routeid %q
Error message
invalid routeid %q
What it means
RegisterTrustedLeaf registers an RPC client as a trusted leaf link and binds a route to it. Before doing anything it validates the routeId with isBindableRouteId, which rejects empty routeIds and any routeId starting with the control prefix or the link-route prefix (those namespaces are reserved for internal router traffic). If the routeId falls in a reserved/empty namespace, the registration is refused with this error.
Source
Thrown at pkg/wshutil/wshrouter.go:638
if lm == nil {
return nil
}
lmCopy := *lm
return &lmCopy
}
func (router *WshRouter) GetLinkIdForRoute(routeId string) baseds.LinkId {
lm := router.getLinkForRoute(routeId)
if lm == nil {
return baseds.NoLinkId
}
return lm.linkId
}
// only for leaves
func (router *WshRouter) RegisterTrustedLeaf(rpc AbstractRpcClient, routeId string) (baseds.LinkId, error) {
if !isBindableRouteId(routeId) {
return 0, fmt.Errorf("invalid routeid %q", routeId)
}
linkId := router.RegisterUntrustedLink(rpc)
router.trustLink(linkId, LinkKind_Leaf)
router.bindRoute(linkId, routeId, true)
return linkId, nil
}
// only for routers
func (router *WshRouter) RegisterTrustedRouter(rpc AbstractRpcClient) baseds.LinkId {
linkId := router.RegisterUntrustedLink(rpc)
router.trustLink(linkId, LinkKind_Router)
return linkId
}
func (router *WshRouter) RegisterUpstream(rpc AbstractRpcClient) baseds.LinkId {
if router.IsRootRouter() {
panic("cannot register upstream for root router")
}View on GitHub (pinned to a4447c1563)
Solutions
- Check the routeId value at the call site; ensure it is a non-empty, user-level route name that does not start with the control prefix or the link-route prefix
- Guard the call with isBindableRouteId semantics: skip or fix calls where routeId is empty or prefixed with the reserved prefixes
- Trace where the routeId is generated (config, blockid, connection id) and fix the generation so it produces a valid named route
Example fix
// before
linkId, err := router.RegisterTrustedLeaf(rpc, routeId) // routeId may be "" or "*ctrl:..."
// after
if routeId == "" || strings.HasPrefix(routeId, ControlPrefix) || strings.HasPrefix(routeId, RoutePrefix_Link) {
return fmt.Errorf("refusing to register leaf with reserved routeid %q", routeId)
}
linkId, err := router.RegisterTrustedLeaf(rpc, routeId) Defensive patterns
Strategy: validation
Validate before calling
func validLeafRouteId(id string) bool {
return id != "" && !strings.HasPrefix(id, ControlPrefix) && !strings.HasPrefix(id, RoutePrefix_Link)
}
if !validLeafRouteId(routeId) {
return fmt.Errorf("cannot register leaf: invalid routeid %q", routeId)
}
linkId, err := router.RegisterTrustedLeaf(rpc, routeId) Type guard
func isSet(s string) bool { return strings.TrimSpace(s) != "" }
if !isSet(routeId) { return } Prevention
- Always build routeIds from non-empty named sources, never raw internal ids
- Never reuse control-prefix or link-prefix route strings for leaf registration
- Log the routeId at the call site before registering to catch empty/generated values early
When it happens
Trigger: Calling WshRouter.RegisterTrustedLeaf(rpc, routeId) with routeId == "", a routeId beginning with ControlPrefix (control-channel namespace), or a routeId beginning with RoutePrefix_Link (per-link route namespace).
Common situations: Constructing a routeId programmatically from a variable that is empty or unset; accidentally passing an internal control/link route id (e.g. one obtained from the router's own reserved prefixes) to RegisterTrustedLeaf instead of a normal named route; copy-pasting a control-channel route string into leaf registration code.
Related errors
- cannot unbind %q to NoLinkId
- cannot bindroute %q to NoLinkId
- router cannot register %q route (invalid routeid)
- cannot bind route %q, no link with id %d found
- cannot bind route %q, link %d is not trusted
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/17458eaaeed883b3.
Report an issue: GitHub.