{"record":{"id":"2445e319f1db7be9","repo":"HKUDS/Vibe-Trading","slug":"token-issue-path-must-differ-from-path-the-websoc","errorCode":null,"errorMessage":"token_issue_path must differ from path (the WebSocket upgrade path)","messagePattern":"token_issue_path must differ from path \\(the WebSocket upgrade path\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/channels/websocket.py","lineNumber":130,"sourceCode":"            raise ValueError('path must start with \"/\"')\n        return _normalize_config_path(value)\n\n    @field_validator(\"token_issue_path\")\n    @classmethod\n    def token_issue_path_format(cls, value: str) -> str:\n        value = value.strip()\n        if not value:\n            return \"\"\n        if not value.startswith(\"/\"):\n            raise ValueError('token_issue_path must start with \"/\"')\n        return _normalize_config_path(value)\n\n    @model_validator(mode=\"after\")\n    def token_issue_path_differs_from_ws_path(self) -> Self:\n        if not self.token_issue_path:\n            return self\n        if _normalize_config_path(self.token_issue_path) == _normalize_config_path(self.path):\n            raise ValueError(\"token_issue_path must differ from path (the WebSocket upgrade path)\")\n        return self\n\n    @model_validator(mode=\"after\")\n    def wildcard_host_requires_auth(self) -> Self:\n        if self.host not in (\"0.0.0.0\", \"::\"):\n            return self\n        if self.token.strip() or self.token_issue_secret.strip():\n            return self\n        raise ValueError(\n            \"host is 0.0.0.0 (all interfaces) but neither token nor \"\n            \"token_issue_secret is set — set one to prevent unauthenticated access\"\n        )\n\n\ndef publish_runtime_model_update(\n    bus: MessageBus,\n    model: str,\n    model_preset: str | None,","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/channels/websocket.py#L112-L148","documentation":"Raised by a model-level validator when token_issue_path normalizes to the same value as path, the WebSocket upgrade endpoint. Both cannot share one route because the server must distinguish an HTTP token-issuing request from a WebSocket upgrade on the same path.","triggerScenarios":"Setting path=\"/ws\" and token_issue_path=\"/ws\", or values that normalize equal such as \"/ws/\" vs \"/ws\" (_normalize_config_path strips trailing differences). Only fires when token_issue_path is non-empty.","commonSituations":"Copy-paste error where both fields were given the same value; setting token_issue_path='/' or to the WS path while experimenting; normalization surprises like adding a trailing slash thinking it makes a different route.","solutions":["Change token_issue_path to a distinct route, e.g. \"/issue-token\"","Keep path: /ws and only set token_issue_path when you actually serve tokens over HTTP"],"exampleFix":"# before\npath = \"/ws\"\ntoken_issue_path = \"/ws\"\n# after\npath = \"/ws\"\ntoken_issue_path = \"/issue-token\"","handlingStrategy":"validation","validationCode":"from agent.src.channels.websocket import _normalize_config_path\n\nif token_issue_path and _normalize_config_path(token_issue_path) == _normalize_config_path(path):\n    raise SystemExit(\"token_issue_path must differ from WebSocket path — pick e.g. /issue-token\")","typeGuard":"def paths_conflict(ws: str, issue: str) -> bool:\n    return bool(issue) and _normalize_config_path(issue) == _normalize_config_path(ws)","tryCatchPattern":null,"preventionTips":["Use obviously distinct route names (/ws vs /issue-token)","Remember trailing slashes are normalized away — they do not create new routes"],"tags":["websocket","route-conflict","config-validation"],"backgroundTag":"config-validation-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}