{"record":{"id":"17458eaaeed883b3","repo":"wavetermdev/waveterm","slug":"invalid-routeid-q","errorCode":null,"errorMessage":"invalid routeid %q","messagePattern":"invalid routeid %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshrouter.go","lineNumber":638,"sourceCode":"\tif lm == nil {\n\t\treturn nil\n\t}\n\tlmCopy := *lm\n\treturn &lmCopy\n}\n\nfunc (router *WshRouter) GetLinkIdForRoute(routeId string) baseds.LinkId {\n\tlm := router.getLinkForRoute(routeId)\n\tif lm == nil {\n\t\treturn baseds.NoLinkId\n\t}\n\treturn lm.linkId\n}\n\n// only for leaves\nfunc (router *WshRouter) RegisterTrustedLeaf(rpc AbstractRpcClient, routeId string) (baseds.LinkId, error) {\n\tif !isBindableRouteId(routeId) {\n\t\treturn 0, fmt.Errorf(\"invalid routeid %q\", routeId)\n\t}\n\tlinkId := router.RegisterUntrustedLink(rpc)\n\trouter.trustLink(linkId, LinkKind_Leaf)\n\trouter.bindRoute(linkId, routeId, true)\n\treturn linkId, nil\n}\n\n// only for routers\nfunc (router *WshRouter) RegisterTrustedRouter(rpc AbstractRpcClient) baseds.LinkId {\n\tlinkId := router.RegisterUntrustedLink(rpc)\n\trouter.trustLink(linkId, LinkKind_Router)\n\treturn linkId\n}\n\nfunc (router *WshRouter) RegisterUpstream(rpc AbstractRpcClient) baseds.LinkId {\n\tif router.IsRootRouter() {\n\t\tpanic(\"cannot register upstream for root router\")\n\t}","sourceCodeStart":620,"sourceCodeEnd":656,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshrouter.go#L620-L656","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nlinkId, err := router.RegisterTrustedLeaf(rpc, routeId) // routeId may be \"\" or \"*ctrl:...\"\n// after\nif routeId == \"\" || strings.HasPrefix(routeId, ControlPrefix) || strings.HasPrefix(routeId, RoutePrefix_Link) {\n    return fmt.Errorf(\"refusing to register leaf with reserved routeid %q\", routeId)\n}\nlinkId, err := router.RegisterTrustedLeaf(rpc, routeId)","handlingStrategy":"validation","validationCode":"func validLeafRouteId(id string) bool {\n    return id != \"\" && !strings.HasPrefix(id, ControlPrefix) && !strings.HasPrefix(id, RoutePrefix_Link)\n}\nif !validLeafRouteId(routeId) {\n    return fmt.Errorf(\"cannot register leaf: invalid routeid %q\", routeId)\n}\nlinkId, err := router.RegisterTrustedLeaf(rpc, routeId)","typeGuard":"func isSet(s string) bool { return strings.TrimSpace(s) != \"\" }\nif !isSet(routeId) { return }","tryCatchPattern":null,"preventionTips":["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"],"tags":["go","wshrouter","routing","invalid-argument"],"backgroundTag":"invalid-route-id","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}