temporalio/temporal · error

missing Legacy Query in PollWorkflowTaskQueueResponse

Error message

missing Legacy Query in PollWorkflowTaskQueueResponse

What it means

For legacy queries, the poll response must contain task.Query; respondQueryTaskCompleted rejects responses where Query is nil because there is no query to answer. This distinguishes a plain workflow task from a legacy query task.

Source

Thrown at common/testing/taskpoller/taskpoller.go:480

	if err != nil {
		return nil, err
	}

	return resp, nil
}

func (p *workflowTaskPoller) respondQueryTaskCompleted(
	ctx context.Context,
	task *workflowservice.PollWorkflowTaskQueueResponse,
	reply *workflowservice.RespondQueryTaskCompletedRequest,
	err error,
) (*workflowservice.RespondQueryTaskCompletedResponse, error) {
	p.t.Helper()
	if task == nil {
		return nil, errors.New("missing PollWorkflowTaskQueueResponse")
	}
	if task.Query == nil {
		return nil, errors.New("missing Legacy Query in PollWorkflowTaskQueueResponse")
	}
	if reply == nil {
		return nil, errors.New("missing RespondQueryTaskCompletedRequest")
	}

	// setting the fields for RespondQueryTaskCompletedResponse
	if reply.Namespace == "" {
		reply.Namespace = p.namespace
	}
	if reply.TaskToken == nil {
		reply.TaskToken = task.TaskToken
	}

	if err != nil {
		reply.ErrorMessage = err.Error()
		reply.Failure = &failurepb.Failure{
			Message: err.Error(),
		}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Route the polled task to HandleTask instead of HandleQuery when task.Query is nil
  2. Dispatch legacy queries through the legacy query path so the server includes Query in the poll response
  3. In mocks, populate resp.Query = &querypb.WorkflowQuery{...} before invoking handleQuery

Example fix

// before
poller.HandleQuery(ctx, task, reply) // task.Query is nil
// after
if task.Query == nil {
    poller.HandleTask(ctx, task, reply)
} else {
    poller.HandleQuery(ctx, task, reply)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if task != nil && task.Query == nil {
    // route to HandleTask instead of HandleQuery
}

Type guard

func isLegacyQueryTask(t *workflowservice.PollWorkflowTaskQueueResponse) bool {
    return t != nil && t.Query != nil
}

Try / catch

if !isLegacyQueryTask(task) {
    return poller.HandleTask(ctx, task, reply)
}
return poller.HandleQuery(ctx, task, reply)

Prevention

When it happens

Trigger: handleQuery receives a PollWorkflowTaskQueueResponse whose Query field is nil — i.e. a normal workflow task was polled but routed to the query handler.

Common situations: Mixing up handleTask and handleQuery in test code; server/mock delivered a regular poll task instead of a legacy query task (query not sent via legacy path); SDK/version mismatch where queries no longer ride workflow-task polls.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/e6fb34c672c2ba78. Report an issue: GitHub.