dapr/dapr · error
received completion for task type %q while watching %q
Error message
received completion for task type %q while watching %q
What it means
Thrown by ClusterTasksBackend while streaming completion notifications for a task: the watcher subscribed with metadata executor.MetadataTaskType=<taskType>, but a response arrives whose task-type header differs from the one being watched. This means the completion stream delivered a completion event for a different task type, which would otherwise be unmarshalled into the wrong resp, so the stream is aborted with this error.
Source
Thrown at pkg/runtime/wfengine/backends/actors/clustertasks.go:358
// completion only to a watcher of its own type; the stream-side check
// below stays as the guard for untyped deliveries.
sreq := internalsv1pb.
NewInternalInvokeRequest(executor.MethodWatchComplete).
WithActor(be.executorActorType, key).
WithContentType(invokev1.ProtobufContentType).
WithMetadata(map[string][]string{executor.MetadataTaskType: {taskType}})
return router.CallStream(ctx, sreq, func(res *internalsv1pb.InternalInvokeResponse) (bool, error) {
if res == nil {
return false, errors.New("received nil response from task completion")
}
if res.GetStatus().GetCode() == int32(codes.Aborted) {
return false, api.ErrTaskCancelled
}
if v, ok := res.GetHeaders()[executor.MetadataTaskType]; ok && len(v.GetValues()) > 0 && v.GetValues()[0] != taskType {
return false, fmt.Errorf("received completion for task type %q while watching %q", v.GetValues()[0], taskType)
}
if err := proto.Unmarshal(res.GetMessage().GetData().GetValue(), resp); err != nil {
return false, err
}
return true, nil
})
}
View on GitHub (pinned to 74ad417027)
Solutions
- Verify both task types and their watchers run on dapr versions that agree on the MetadataTaskType header contract
- Check daprd logs to see which task type's completion was misrouted and whether duplicate watchers exist for the same stream
- If running several task types, ensure each watcher is started against its own task type subscription and old watchers are stopped
- Report/reproduce with the quoted types — a mismatch here indicates a routing bug in the completion fan-out, not user configuration
Defensive patterns
Strategy: try-catch
Try / catch
Catch the error from the watch call and compare the two quoted task types: if they belong to different workflows/components, stop duplicate watchers and restart the affected one; do not swallow it, since proceeding would attribute completions to the wrong task.
Prevention
- Run one watcher per task type and ensure watchers are closed before starting replacements
- Upgrade all daprd sidecars together when the task-completion header contract changes
- When running multiple task types per app, tag logs with the watched type to catch misrouting early
When it happens
Trigger: A completion callback routed to a watcher of another task type — e.g. two workflow backends sharing one callback actor/stream and the routing header not filtering correctly; an upstream daprd sending a completion without honoring or echoing the watched task type in headers; a mismatched subscription after task types were renamed between versions.
Common situations: Running multiple distinct task types on the same app where one watcher receives the other's events; version skew between daprd versions that changed the task-type header contract; duplicate watchers started for the same callback stream.
Related errors
- response does not contain the required fields in the leading
- response metadata found in non-leading chunk
- server is closed
- unable to read from binding: %w
- unable to subscribe: %w
AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16).
Data as JSON: /api/errors/d1204eba5b5e7d2d.
Report an issue: GitHub.