{"record":{"id":"b34f0b2cebc0af6c","repo":"github/copilot-sdk","slug":"invalid-arguments-use-on-lifecycle-handler-or-on","errorCode":null,"errorMessage":"Invalid arguments: use on_lifecycle(handler) or on_lifecycle(event_type, handler)","messagePattern":"Invalid arguments: use on_lifecycle\\(handler\\) or on_lifecycle\\(event_type, handler\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/copilot/client.py","lineNumber":4071,"sourceCode":"                            self._lifecycle_handlers.remove(wildcard_handler)\n\n                return unsubscribe_wildcard\n            elif isinstance(event_type_or_handler, str) and handler is not None:\n                # Typed subscription: on(event_type, handler)\n                event_type = cast(SessionLifecycleEventType, event_type_or_handler)\n                if event_type not in self._typed_lifecycle_handlers:\n                    self._typed_lifecycle_handlers[event_type] = []\n                self._typed_lifecycle_handlers[event_type].append(handler)\n\n                def unsubscribe_typed() -> None:\n                    with self._lifecycle_handlers_lock:\n                        handlers = self._typed_lifecycle_handlers.get(event_type, [])\n                        if handler in handlers:\n                            handlers.remove(handler)\n\n                return unsubscribe_typed\n            else:\n                raise ValueError(\n                    \"Invalid arguments: use on_lifecycle(handler) \"\n                    \"or on_lifecycle(event_type, handler)\"\n                )\n\n    def _dispatch_lifecycle_event(self, event: SessionLifecycleEvent) -> None:\n        \"\"\"Dispatch a lifecycle event to all registered handlers.\"\"\"\n        with self._lifecycle_handlers_lock:\n            # Copy handlers to avoid holding lock during callbacks\n            typed_handlers = list(self._typed_lifecycle_handlers.get(event.type, []))\n            wildcard_handlers = list(self._lifecycle_handlers)\n\n        # Dispatch to typed handlers\n        for handler in typed_handlers:\n            try:\n                handler(event)\n            except Exception:\n                pass  # Ignore handler errors\n","sourceCodeStart":4053,"sourceCodeEnd":4089,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/client.py#L4053-L4089","documentation":"on_lifecycle() supports two overloads: on_lifecycle(handler) for all events, or on_lifecycle(event_type, handler) for a specific event type. If neither signature matches (e.g. zero arguments, three arguments, or two non-handler-first args), the client raises this ValueError.","triggerScenarios":"Calling client.on_lifecycle() with no arguments, with more than two arguments, or with two positional arguments where the first is not a recognized SessionLifecycleEventType (e.g. passing a string event name).","commonSituations":"Passing event type as a raw string like \"session.created\" instead of the enum; passing keyword arguments (handler=...) which the positional-overload dispatcher doesn't recognize; typos in argument order like on_lifecycle(handler, event_type).","solutions":["Call on_lifecycle(handler) with exactly one handler for all lifecycle events","Or call on_lifecycle(event_type, handler) with the event type first, using the SessionLifecycleEventType enum value","Remove keyword arguments; the dispatcher matches positional overloads only","Swap argument order if you wrote on_lifecycle(handler, event_type)"],"exampleFix":"// before\nclient.on_lifecycle(\"session.created\", on_created)\n// after\nfrom copilot.generated.protocol import SessionLifecycleEventType\nclient.on_lifecycle(SessionLifecycleEventType.SESSION_CREATED, on_created)","handlingStrategy":"validation","validationCode":"from copilot.generated.protocol import SessionLifecycleEventType\nassert isinstance(event_type, SessionLifecycleEventType)\nassert callable(handler)\nclient.on_lifecycle(event_type, handler)","typeGuard":"def is_valid_lifecycle_args(*args) -> bool:\n    return len(args) == 1 and callable(args[0]) or (\n        len(args) == 2 and isinstance(args[0], SessionLifecycleEventType) and callable(args[1])\n    )","tryCatchPattern":"try:\n    client.on_lifecycle(event_type, handler)\nexcept ValueError as e:\n    if \"Invalid arguments\" in str(e):\n        client.on_lifecycle(handler)  # fall back to all-events subscription\n    else:\n        raise","preventionTips":["Use the SessionLifecycleEventType enum, not raw strings","Match one of the two documented positional signatures exactly","Put event_type first, handler second; never pass keyword args"],"tags":["value-error","api-misuse","arguments","python"],"backgroundTag":"invalid-argument","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}