{"record":{"id":"160c5a3a34c59233","repo":"wavetermdev/waveterm","slug":"router-cannot-register-q-route-invalid-routeid","errorCode":null,"errorMessage":"router cannot register %q route (invalid routeid)","messagePattern":"router cannot register %q route \\(invalid routeid\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wshutil/wshrouter.go","lineNumber":772,"sourceCode":"\t\treturn err\n\t}\n\tlm := router.getLinkMeta(linkId)\n\tif lm != nil {\n\t\tlog.Printf(\"wshrouter unbind route %q from %s\", routeId, lm.Name())\n\t}\n\trouter.unannounceUpstream(routeId)\n\tif router.IsRootRouter() {\n\t\trouter.unsubscribeFromBroker(routeId)\n\t}\n\treturn nil\n}\n\nfunc (router *WshRouter) bindRouteLocally(linkId baseds.LinkId, routeId string, isSourceRoute bool) error {\n\tif linkId == baseds.NoLinkId {\n\t\treturn fmt.Errorf(\"cannot bindroute %q to NoLinkId\", routeId)\n\t}\n\tif !isBindableRouteId(routeId) {\n\t\treturn fmt.Errorf(\"router cannot register %q route (invalid routeid)\", routeId)\n\t}\n\trouter.lock.Lock()\n\tdefer router.lock.Unlock()\n\tlm := router.linkMap[linkId]\n\tif lm == nil {\n\t\treturn fmt.Errorf(\"cannot bind route %q, no link with id %d found\", routeId, linkId)\n\t}\n\tif !lm.trusted {\n\t\treturn fmt.Errorf(\"cannot bind route %q, link %d is not trusted\", routeId, linkId)\n\t}\n\tif isSourceRoute {\n\t\tif lm.linkKind != LinkKind_Leaf {\n\t\t\treturn fmt.Errorf(\"cannot bind source route %q to link %d (link is not a leaf)\", routeId, linkId)\n\t\t}\n\t\tif lm.sourceRouteId != \"\" && lm.sourceRouteId != routeId {\n\t\t\treturn fmt.Errorf(\"cannot bind source route %q to link %d (link already has source route %q)\", routeId, linkId, lm.sourceRouteId)\n\t\t}\n\t\tlm.sourceRouteId = routeId","sourceCodeStart":754,"sourceCodeEnd":790,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wshutil/wshrouter.go#L754-L790","documentation":"bindRouteLocally validates the routeId with isBindableRouteId before installing it in routeMap. Empty routeIds and routeIds in the reserved namespaces (ControlPrefix, RoutePrefix_Link) are not bindable, because those prefixes are used internally for control traffic and per-link routes; using them for a normal bind would shadow or collide with router internals.","triggerScenarios":"Calling WshRouter.bindRoute / bindRouteLocally with routeId == \"\" or a routeId starting with the control prefix or the link-route prefix.","commonSituations":"An empty routeId from an unset config field or from a remote announce message with a blank route; accidentally rebinding an internal per-link route id; forwarding a routeannounce/routeunbind control message's route value into bindRoute without stripping internal prefixes.","solutions":["Verify the routeId is a non-empty named route that does not start with ControlPrefix or RoutePrefix_Link","Fix the source of the routeId (remote announce payload, config value) so it produces a valid route name","Pre-check with the same rules as isBindableRouteId before calling bindRoute"],"exampleFix":"// before\nerr := router.bindRoute(linkId, routeId, true) // routeId could be \"\" or \"*link:...\"\n// after\nif !isBindableRouteId(routeId) {\n    return fmt.Errorf(\"skipping bind of reserved/empty routeid %q\", routeId)\n}\nerr := router.bindRoute(linkId, routeId, true)","handlingStrategy":"validation","validationCode":"if routeId == \"\" || strings.HasPrefix(routeId, ControlPrefix) || strings.HasPrefix(routeId, RoutePrefix_Link) {\n    return fmt.Errorf(\"invalid routeid %q for bind\", routeId)\n}\nerr := router.bindRoute(linkId, routeId, true)","typeGuard":"func bindableRouteId(s string) bool {\n    return s != \"\" && !strings.HasPrefix(s, ControlPrefix) && !strings.HasPrefix(s, RoutePrefix_Link)\n}\nif !bindableRouteId(routeId) { return }","tryCatchPattern":"err := router.bindRoute(linkId, routeId, isSource)\nif err != nil && strings.Contains(err.Error(), \"invalid routeid\") {\n    // inspect the remote announce payload / config value that produced routeId\n}","preventionTips":["Validate routeIds from remote announce messages before binding them","Reject empty route fields from config at load time","Keep internal-prefixed route names out of any user-facing route config"],"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"}