{"record":{"id":"1721aa556e95a6cb","repo":"canopy-network/canopy","slug":"1-1721aa","errorCode":"1","errorMessage":"Contract fsm_id is not set","messagePattern":"Contract fsm_id is not set","errorType":"exception","errorClass":"PluginError","httpStatus":null,"severity":"error","filePath":"plugin/python/contract/plugin.py","lineNumber":186,"sourceCode":"\n    async def _handshake(self) -> None:\n        \"\"\"Handshake sends the contract configuration to the FSM and awaits a reply.\"\"\"\n        logger.info(\"Handshaking with FSM\")\n\n        # Send config to FSM\n        message = PluginToFSM()\n        message.id = 0\n        message.config.CopyFrom(self.plugin_config)\n\n        await self._send_proto_msg(message)\n\n        # Wait for response - the FSM will send back its config\n        # This will be handled in _listen_for_inbound\n\n    async def state_read(self, contract: Contract, request: PluginStateReadRequest) -> PluginStateReadResponse:\n        \"\"\"StateRead sends a state read request to FSM and waits for response.\"\"\"\n        if contract.fsm_id is None:\n            raise PluginError(1, \"plugin\", \"Contract fsm_id is not set\")\n\n        fsm_id = contract.fsm_id\n\n        # Create future for response\n        future: asyncio.Future = asyncio.Future()\n        self._pending[fsm_id] = future\n        self._request_contracts[fsm_id] = contract\n\n        # Send request\n        message = PluginToFSM()\n        message.id = fsm_id\n        message.state_read.CopyFrom(request)\n\n        try:\n            logger.debug(f\"0x{fsm_id:x}: state_read\")\n            await self._send_proto_msg(message)\n\n            # Wait for response with timeout","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/plugin/python/contract/plugin.py#L168-L204","documentation":"Raised in state_read when the Contract object passed in has no fsm_id assigned. The FSM routes plugin messages by fsm_id, so a request without one cannot be correlated to a contract and would be rejected or misrouted.","triggerScenarios":"Thrown at plugin/python/contract/plugin.py:186 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Ensure the contract is registered with the FSM (handshake/registration assigns fsm_id) before calling state_read.","Do not construct ad-hoc Contract objects for state reads; pass the FSM-created contract instance.","Check that deserialization/creation code that builds Contract objects populates fsm_id."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}