BerriAI/litellm · error · Exception

Task {task_id} ended with state: {state}

Error message

Task {task_id} ended with state: {state}

What it means

Generic Exception raised while polling a Pydantic AI task: the task's status.state became 'failed' or 'canceled' before reaching 'completed'. The message echoes the task id and terminal state from the agent's response.

Source

Thrown at litellm/a2a_protocol/providers/pydantic_ai_agents/transformation.py:147

                json=poll_request,
                headers={
                    **(agent_extra_headers or {}),
                    "Content-Type": "application/json",
                },
            )
            response.raise_for_status()
            poll_data = _STR_KEY_DICT_ADAPTER.validate_python(response.json())

            result = _STR_KEY_DICT_ADAPTER.validate_python(poll_data.get("result", {}))
            status = _STR_KEY_DICT_ADAPTER.validate_python(result.get("status", {}))
            state = status.get("state", "")

            verbose_logger.debug("Pydantic AI: Poll attempt %s/%s, state=%s", attempt + 1, max_attempts, state)

            if state == "completed":
                return poll_data
            elif state in ("failed", "canceled"):
                raise Exception(f"Task {task_id} ended with state: {state}")

            await asyncio.sleep(poll_interval)

        raise TimeoutError(f"Task {task_id} did not complete within {max_attempts * poll_interval} seconds")

    @staticmethod
    async def _send_and_poll_raw(
        api_base: str,
        request_id: str,
        params: "_SupportsModelDump | _SupportsPydanticDict | Mapping[str, object]",
        timeout: float = 60.0,
        agent_extra_headers: dict[str, str] | None = None,
    ) -> dict[str, object]:
        """
        Send a request to Pydantic AI agent and return the raw task response.

        This is an internal method used by both non-streaming and streaming handlers.
        Returns the raw Pydantic AI task format with history/artifacts.

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Inspect the Pydantic AI agent's logs/servers for the root cause of the failed task
  2. Validate the request payload (message, tools config) against what the agent accepts
  3. If cancellation is expected, handle this exception and surface it as a user-facing cancellation instead of an error
Defensive patterns

Strategy: try-catch

Try / catch

try:
    result = await PydanticAIHandler.handle_non_streaming(...)
except Exception as e:
    msg = str(e)
    if "ended with state:" in msg:
        state = msg.rsplit(":", 1)[-1].strip()
        if state == "canceled":
            return cancellation_response()
        return agent_error_response(detail=msg)  # surface agent-side failure
    raise

Prevention

When it happens

Trigger: PydanticAITransformation polling loop observes state='failed' or 'canceled' in result.status.state of the polled task before completion (agent raised an error, tool crashed, or the task was canceled).

Common situations: Bugs in the deployed Pydantic AI agent (invalid tools, missing API keys in the agent env); user- or system-initiated cancellation; agent runtime OOM/timeout surfacing as failed state.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/611f66fbe0978852. Report an issue: GitHub.