wavetermdev/waveterm · error
cannot bind route %q, link %d is not trusted
Error message
cannot bind route %q, link %d is not trusted
What it means
bindRouteLocally only allows routes to be bound to trusted links. After finding the link metadata (lm), it checks lm.trusted; if the link was registered as untrusted (e.g. via RegisterUntrustedLink without a subsequent trustLink call), binding a route to it is refused, since untrusted links must not claim routes.
Source
Thrown at pkg/wshutil/wshrouter.go:781
}
return nil
}
func (router *WshRouter) bindRouteLocally(linkId baseds.LinkId, routeId string, isSourceRoute bool) error {
if linkId == baseds.NoLinkId {
return fmt.Errorf("cannot bindroute %q to NoLinkId", routeId)
}
if !isBindableRouteId(routeId) {
return fmt.Errorf("router cannot register %q route (invalid routeid)", routeId)
}
router.lock.Lock()
defer router.lock.Unlock()
lm := router.linkMap[linkId]
if lm == nil {
return fmt.Errorf("cannot bind route %q, no link with id %d found", routeId, linkId)
}
if !lm.trusted {
return fmt.Errorf("cannot bind route %q, link %d is not trusted", routeId, linkId)
}
if isSourceRoute {
if lm.linkKind != LinkKind_Leaf {
return fmt.Errorf("cannot bind source route %q to link %d (link is not a leaf)", routeId, linkId)
}
if lm.sourceRouteId != "" && lm.sourceRouteId != routeId {
return fmt.Errorf("cannot bind source route %q to link %d (link already has source route %q)", routeId, linkId, lm.sourceRouteId)
}
lm.sourceRouteId = routeId
} else {
if lm.linkKind != LinkKind_Router {
return fmt.Errorf("cannot bind route %q to link %d (link is not a router)", routeId, linkId)
}
}
router.routeMap[routeId] = linkId
return nil
}
View on GitHub (pinned to a4447c1563)
Solutions
- Mark the link trusted before binding: call the router's trust mechanism (e.g. RegisterTrustedLeaf for leaves, or the trust step used for router links)
- If the link should stay untrusted, do not bind a route to it and route messages by linkId instead
- On reconnect, re-run the trust flow for the new link before rebinding routes
Example fix
// before
linkId := router.RegisterUntrustedLink(rpc)
err := router.bindRoute(linkId, routeId, true) // link not trusted
// after
linkId, err := router.RegisterTrustedLeaf(rpc, routeId)
if err != nil {
return err
} Defensive patterns
Strategy: validation
Validate before calling
// prefer the combined API which registers AND trusts AND binds
linkId, err := router.RegisterTrustedLeaf(rpc, routeId)
if err != nil {
return err
} Try / catch
err := router.bindRoute(linkId, routeId, isSource)
if err != nil && strings.Contains(err.Error(), "is not trusted") {
// trust the link first, then retry the bind
} Prevention
- Use RegisterTrustedLeaf for leaves instead of RegisterUntrustedLink + manual bind
- Complete the trust step before any route binding in custom router wiring
- Re-run the trust flow after every reconnect
When it happens
Trigger: Calling WshRouter.bindRoute for a link registered with RegisterUntrustedLink that was never trusted via trustLink/TrustLink/MarkLinkAsTrusted, then attempting to bind a route to it.
Common situations: Registering a downstream connection as untrusted (block-level wsh connections) and then trying to claim a stable route on it; forgetting the trust step in a custom router setup; link trust state lost after reconnect so the new link is untrusted while old code still binds routes.
Related errors
- invalid routeid %q
- 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
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/0caeb4eca8981932.
Report an issue: GitHub.