{"record":{"id":"d0056fd2cba0a808","repo":"ruvnet/RuView","slug":"unknown-topic-topic","errorCode":null,"errorMessage":"Unknown topic: {topic}","messagePattern":"Unknown topic: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"plans/phase2-architecture/api-architecture.md","lineNumber":489,"sourceCode":"        }, client_id)\n    \n    def disconnect(self, client_id: str):\n        \"\"\"Remove WebSocket connection\"\"\"\n        if client_id in self.active_connections:\n            del self.active_connections[client_id]\n            \n            # Remove from all subscriptions\n            for topic in self.subscriptions:\n                self.subscriptions[topic].discard(client_id)\n            \n            # Clean up client info\n            if client_id in self.client_info:\n                del self.client_info[client_id]\n    \n    async def subscribe(self, client_id: str, topic: str, filters: dict = None):\n        \"\"\"Subscribe client to topic\"\"\"\n        if topic not in self.subscriptions:\n            raise ValueError(f\"Unknown topic: {topic}\")\n        \n        self.subscriptions[topic].add(client_id)\n        self.client_info[client_id]['subscriptions'].add(topic)\n        \n        # Store filters if provided\n        if filters:\n            if 'filters' not in self.client_info[client_id]:\n                self.client_info[client_id]['filters'] = {}\n            self.client_info[client_id]['filters'][topic] = filters\n        \n        # Send confirmation\n        await self.send_personal_message({\n            'type': 'subscription',\n            'topic': topic,\n            'status': 'subscribed',\n            'filters': filters\n        }, client_id)\n    ","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/plans/phase2-architecture/api-architecture.md#L471-L507","documentation":"Spec code in plans/phase2-architecture/api-architecture.md: the subscription manager's subscribe(client_id, topic, filters) raises ValueError('Unknown topic: ...') when topic is not a key in self.subscriptions. The registry of valid topics is fixed at init; subscribing does not create topics, so only pre-registered names are accepted.","triggerScenarios":"A WebSocket client subscribing with a typo'd or unregistered topic name (e.g. 'poses/live' when the registry has 'pose.live'); topic strings taken from user input without validation; a topic added server-side but the client using an older name.","commonSituations":"Client/server topic vocabulary drift after a deploy; copy-paste of topic names from docs that renamed them; missing strip/lower normalization so 'pose.live ' fails.","solutions":["Use the exact topic names registered in the subscription manager (expose a list-topics call/endpoint for clients)","Normalize input before subscribing: topic.strip() (and case-fold if the registry does)","Register new topics in the manager's init before clients subscribe to them","Catch the ValueError at the WebSocket boundary and send a client-friendly error with the valid topic list"],"exampleFix":"# before\nawait manager.subscribe(client_id, \"poses/live\")  # ValueError: Unknown topic\n\n# after\nif topic not in manager.subscriptions:\n    await send_json(ws, {\"error\": \"unknown topic\", \"valid\": sorted(manager.subscriptions)})\nelse:\n    await manager.subscribe(client_id, topic)","handlingStrategy":"validation","validationCode":"topic = topic.strip()\nif topic not in manager.subscriptions:\n    await ws.send_json({\"error\": \"unknown topic\", \"valid_topics\": sorted(manager.subscriptions)})\n    return\nawait manager.subscribe(client_id, topic)","typeGuard":"def is_known_topic(manager, topic: object) -> bool:\n    return isinstance(topic, str) and topic in manager.subscriptions","tryCatchPattern":"try:\n    await manager.subscribe(client_id, topic)\nexcept ValueError as e:\n    await ws.send_json({\"error\": str(e), \"valid_topics\": sorted(manager.subscriptions)})","preventionTips":["Publish the valid topic list to clients (docs endpoint or connection handshake) so they never guess","Normalize topic strings (strip whitespace) before subscribing","Treat unknown-topic ValueErrors as client input errors (send a helpful message), not server crashes"],"tags":["websocket","pubsub","validation","python","api","spec","topics"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}