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

  1. Verify both task types and their watchers run on dapr versions that agree on the MetadataTaskType header contract
  2. Check daprd logs to see which task type's completion was misrouted and whether duplicate watchers exist for the same stream
  3. If running several task types, ensure each watcher is started against its own task type subscription and old watchers are stopped
  4. 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

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


AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16). Data as JSON: /api/errors/d1204eba5b5e7d2d. Report an issue: GitHub.