{"record":{"id":"c7e986177d9a7844","repo":"github/copilot-sdk","slug":"canvas-action-no-handler-c7e986","errorCode":"canvas_action_no_handler","errorMessage":"No handler implemented for this canvas action","messagePattern":"No handler implemented for this canvas action","errorType":"error_code","errorClass":"CanvasError","httpStatus":null,"severity":"error","filePath":"python/copilot/canvas.py","lineNumber":192,"sourceCode":"\n        **Experimental.** This type is part of an experimental wire-protocol\n        surface and may change or be removed in future SDK or CLI releases.\n    \"\"\"\n\n    @abstractmethod\n    async def on_open(self, ctx: CanvasProviderOpenRequest) -> CanvasProviderOpenResult:\n        \"\"\"Open a new canvas instance.\n\n        May raise :class:`CanvasError` to surface a structured failure to\n        the host.\n        \"\"\"\n\n    async def on_close(self, ctx: CanvasProviderCloseRequest) -> None:\n        \"\"\"Canvas was closed by the user or agent. Default: no-op.\"\"\"\n\n    async def on_action(self, ctx: CanvasProviderInvokeActionRequest) -> Any:\n        \"\"\"Handle a non-lifecycle action declared by the canvas.\"\"\"\n        raise CanvasError.no_handler()\n","sourceCodeStart":174,"sourceCodeEnd":193,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/canvas.py#L174-L193","documentation":"CanvasProvider.on_action is the hook for handling non-lifecycle canvas actions declared by a canvas. The base-class default implementation raises CanvasError.no_handler() (code 'canvas_action_no_handler'), signalling that the provider subclass did not override on_action for an action it declared. If your canvas declares actions, you must implement this method.","triggerScenarios":"A user or agent invokes an action on a canvas whose provider subclass does not override on_action — the declared action reaches the base-class stub, which always raises.","commonSituations":"Developers define canvas actions in their canvas manifest but only override lifecycle hooks (on_open/on_close); a new action is added to the canvas while the provider code is not deployed/updated; the provider is wired to a canvas whose action set changed.","solutions":["Override on_action in your CanvasProvider subclass and implement the declared actions","Route on ctx.request/ctx.action to the correct handler and return a JSON-serializable result","Remove any declared actions your provider does not implement","Add a guard/deployment check that every declared canvas action has a matching on_action branch"],"exampleFix":"// before\nclass MyProvider(CanvasProvider):\n    async def on_open(self, ctx): ...\n    # on_action not overridden\n\n// after\nclass MyProvider(CanvasProvider):\n    async def on_action(self, ctx):\n        if ctx.action == \"submit\":\n            return {\"ok\": True}\n        raise CanvasError.no_handler()","handlingStrategy":"try-catch","validationCode":"declared = {a[\"name\"] for a in canvas_manifest.get(\"actions\", [])}\nif declared and not isinstance(provider.on_action, type(CanvasProvider.on_action)):\n    raise RuntimeError(\"canvas declares actions but provider does not override on_action\")","typeGuard":"def implements_on_action(provider) -> bool:\n    return type(provider).on_action is not CanvasProvider.on_action","tryCatchPattern":"try:\n    result = await provider.on_action(ctx)\nexcept CanvasError as e:\n    if e.code == \"canvas_action_no_handler\":\n        result = {\"error\": f\"action {ctx.action} not supported\"}","preventionTips":["Always override on_action when your canvas declares any action","Keep the canvas manifest and provider action handlers in sync (test one against the other)","Deploy provider and canvas definition changes together","Return an explicit 'unsupported action' result for unrecognized actions instead of relying on the base stub"],"tags":["canvas","python","not-implemented","subclassing"],"backgroundTag":"method-not-implemented","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}