micro/go-micro · error
remote task %s ended in state %q
Error message
remote task %s ended in state %q
What it means
Send submits an A2A message and polls the resulting remote task until it reaches a terminal state. The library throws this error when the task finished in a terminal state other than completed (e.g. failed, canceled, rejected), meaning no result text can be returned. The message includes the remote task ID and the actual state string so callers can correlate and diagnose.
Source
Thrown at gateway/a2a/client.go:75
}
return &card, nil
}
// Send sends a text message to the remote agent and returns its reply.
// If the agent returns a task that isn't yet terminal, Send polls
// tasks/get until it completes or ctx is done.
func (c *Client) Send(ctx context.Context, text string) (string, error) {
task, err := c.SendMessage(ctx, Message{
Role: "user",
Kind: "message",
MessageID: uuid.New().String(),
Parts: []Part{{Kind: "text", Text: text}},
})
if err != nil {
return "", err
}
if task.Status.State != stateCompleted {
return "", fmt.Errorf("remote task %s ended in state %q", task.ID, task.Status.State)
}
return artifactsText(task.Artifacts), nil
}
// SendMessage sends an A2A message and returns the resulting terminal task.
// To continue a multi-turn task, pass a Message with TaskID and ContextID set
// to a prior task's id and context id.
func (c *Client) SendMessage(ctx context.Context, message Message) (*Task, error) {
if message.MessageID == "" {
message.MessageID = uuid.New().String()
}
if message.Kind == "" {
message.Kind = "message"
}
if message.Role == "" {
message.Role = "user"
}
res, err := c.call(ctx, "message/send", sendParams{Message: message})View on GitHub (pinned to 24529f1404)
Solutions
- Read the state value in the error; if 'failed', fetch task details or logs from the remote agent for the underlying cause.
- Inspect the task status message/artifacts via the task ID to get agent-reported error details.
- Retry the send if the failure was transient (upstream model/tool outage); implement idempotency keys if the agent supports them.
- Handle 'canceled' explicitly in caller flow (surface to user rather than retrying).
Defensive patterns
Strategy: try-catch
Try / catch
text, err := c.Send(ctx, msg)
if err != nil {
var stateErr *taskStateError // or regex the state from the message
if m := stateRe.FindStringSubmatch(err.Error()); m != nil {
switch m[2] {
case "canceled": return errCanceled
case "failed": return retryableOrNot(err)
}
}
return err
} Prevention
- Parse the quoted state from the error before deciding to retry
- Only retry 'failed' tasks with transient causes
- Surface canceled state to users instead of auto-retrying
- Correlate using the task ID included in the message
- Set agent-side timeouts so tasks fail fast rather than hang
When it happens
Trigger: Calling SendMessage when the remote agent marks the task 'failed' due to a processing error, 'canceled' by the user or a timeout, or any custom terminal state the agent reports other than the library's stateCompleted value.
Common situations: The remote agent rejected the input (invalid parameters, unsupported capability); the task was canceled after a deadline; the agent-side model or tool call crashed mid-task; an operator canceled long-running work.
Related errors
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/f65dac7201285542.
Report an issue: GitHub.