Skip to content

fix: a blocking wait ignores AUTH_REQUIRED and hangs until timeout #36

Description

@msampathkumar

Goal: A blocking wait should return control the moment a task needs authentication, instead of polling until it times out.

User story: As a developer (or CI job) waiting on a task, when the agent pauses the task for authentication I want the CLI to stop and tell me so immediately, so that I can act — instead of the command hanging until --timeout and then reporting a misleading "timeout" error.

Priority: P1 · Area: CLI code · Type: bug

What happens today

The polling loop treats a task as "still running" whenever its state is neither terminal nor INPUT_REQUIRED. It does not account for AUTH_REQUIRED. So a task that pauses at AUTH_REQUIRED keeps getting polled until the request context / --timeout expires, and the CLI then surfaces a timeout error — the user is told the call timed out, not that the agent is waiting for authentication.

This affects the blocking wait that falls back to polling (the send --stream path when the agent does not support streaming).

Root cause (confirmed by code review)

In internal/polling/polling.go:

  • Line 62 — loop condition:
    for !prevState.Status.State.Terminal() && prevState.Status.State != a2a.TaskStateInputRequired {
    a2a.TaskStateAuthRequired is missing, so the loop keeps polling on an auth-paused task.
  • Line 82 — the same omission when deciding whether to yield the task:
    if task.Status.State.Terminal() || task.Status.State == a2a.TaskStateInputRequired {

AUTH_REQUIRED is a real, non-terminal "interrupted" state — the SDK defines it as a2a.TaskStateAuthRequired (= "auth-required") and TaskState.Terminal() correctly returns false for it. So this is purely the CLI's stop condition, not SDK behavior.

Expected behavior

A wait must return promptly on both interrupted states — INPUT_REQUIRED and AUTH_REQUIRED — yielding the task so the caller sees the state and identifiers and can act.

Suggested fix (small)

  • Line 62: add && prevState.Status.State != a2a.TaskStateAuthRequired.
  • Line 82: add || task.Status.State == a2a.TaskStateAuthRequired.
  • Add a table-driven test covering a task that transitions to AUTH_REQUIRED (assert the wait returns the task, not a timeout).

Steps to reproduce

Requires an agent that moves a task to AUTH_REQUIRED and does not advertise streaming (so the poll fallback runs):

  1. a2a send -a <agent-that-pauses-for-auth> --stream "<message>"
  2. Observe the command hang until --timeout, then fail with a timeout error, instead of returning promptly with the AUTH_REQUIRED state.

Acceptance criteria

  • A wait returns promptly when a task reaches AUTH_REQUIRED, reporting taskId, contextId, and the state.
  • It still returns on INPUT_REQUIRED and on terminal states, unchanged.
  • A test asserts the AUTH_REQUIRED case returns the task rather than timing out.

Environment

  • CLI version: a2a version v0.0.0-…1e29dfe94f95+dirty (main 1e29dfe)
  • OS: Linux x86_64

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Priority 1 — missing capability that limits real usebugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions