{"record":{"id":"a77dcf49e025ada5","repo":"langchain-ai/deepagents","slug":"pendingnotification-self-key-r-must-declare-at-l","errorCode":null,"errorMessage":"PendingNotification {self.key!r} must declare at least one action","messagePattern":"PendingNotification (.+?) must declare at least one action","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/notifications.py","lineNumber":125,"sourceCode":"    actions: tuple[NotificationAction, ...]\n    \"\"\"Available actions, rendered as rows in the modal.\"\"\"\n\n    payload: Payload\n    \"\"\"Kind-specific typed data consumed by the action dispatcher.\"\"\"\n\n    def __post_init__(self) -> None:\n        \"\"\"Enforce basic invariants at construction time.\n\n        Raises:\n            ValueError: If `key` is empty, `actions` is empty, or more\n                than one action is marked `primary=True`.\n        \"\"\"\n        if not self.key:\n            msg = \"PendingNotification.key must be non-empty\"\n            raise ValueError(msg)\n        if not self.actions:\n            msg = f\"PendingNotification {self.key!r} must declare at least one action\"\n            raise ValueError(msg)\n        primaries = sum(1 for a in self.actions if a.primary)\n        if primaries > 1:\n            msg = (\n                f\"PendingNotification {self.key!r} has {primaries} primary actions; \"\n                \"at most one is allowed\"\n            )\n            raise ValueError(msg)\n\n\nclass NotificationRegistry:\n    \"\"\"In-memory store of pending notifications.\n\n    Instance-scoped (one per app) so test apps don't pollute each other.\n    Owns the bidirectional key-to-toast-identity binding so callers\n    cannot accidentally desynchronize the click-routing indices.\n    \"\"\"\n\n    def __init__(self) -> None:","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/notifications.py#L107-L143","documentation":"`PendingNotification` must declare at least one action, because a notification with no buttons/commands can never be resolved by the registry. `__post_init__` raises a `ValueError` naming the notification's key when `actions` is empty.","triggerScenarios":"Constructing `PendingNotification(key=\"x\", actions=[])` or `actions=None`, typically when actions are collected dynamically (e.g. filtered from a list that came back empty).","commonSituations":"Filtering actions by permissions and getting an empty list; deserializing a notification from JSON without the actions field; building a purely informational notification that the API doesn't support.","solutions":["Always pass at least one `NotificationAction` (make it primary if it's the sole one)","Filter actions first and skip creating the notification if none survive","Provide a default action such as a 'Dismiss' or 'Open' action"],"exampleFix":"// before\nnote = PendingNotification(key=\"deploy\", actions=[a for a in acts if a.enabled])\n// after\nenabled = [a for a in acts if a.enabled]\nif not enabled:\n    return\nnote = PendingNotification(key=\"deploy\", actions=enabled)","handlingStrategy":"validation","validationCode":"if not actions:\n    raise ValueError(\"PendingNotification requires at least one action\")","typeGuard":"def has_actions(d: dict[str, object]) -> TypeGuard[dict[str, object]]:\n    acts = d.get(\"actions\")\n    return isinstance(acts, list) and len(acts) > 0","tryCatchPattern":"try:\n    note = PendingNotification(key=key, actions=actions)\nexcept ValueError as e:\n    logging.warning(\"dropping notification %r: %s\", key, e)","preventionTips":["Provide a default fallback action (e.g. Dismiss)","Check the filtered action list is non-empty before construction","Never deserialize notifications without the actions field"],"tags":["python","validation","notifications","dataclass"],"backgroundTag":"schema-validation-failed","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}