temporalio/temporal · error

task has no deadline or destination

Error message

task has no deadline or destination

What it means

This error is returned by the Temporal history service's HSM (hierarchical state machine) task generator when a sub-state machine task being generated has neither a deadline nor a destination. The task generator can only schedule tasks that expire by deadline or are routed to a destination; 'transfer' style tasks (immediate, without destination) are not yet implemented, as noted by the in-code TODO.

Source

Thrown at service/history/workflow/task_generator.go:1005

	// NOTE: at the moment deadline is mutually exclusive with destination.
	// This will change when we add the outbound timer queue.
	if task.Deadline() != hsm.Immediate {
		if task.Destination() != "" {
			// TODO: support outbound timer tasks.
			return fmt.Errorf("task cannot have both a deadline and destination due to missing outbound timer queue implementation")
		}
		TrackStateMachineTimer(mutableState, task.Deadline(), taskInfo)
	} else if task.Destination() != "" {
		mutableState.AddTasks(&tasks.StateMachineOutboundTask{
			StateMachineTask: tasks.StateMachineTask{
				WorkflowKey: mutableState.GetWorkflowKey(),
				Info:        taskInfo,
			},
			Destination: task.Destination(),
		})
	} else {
		// TODO: support "transfer" tasks - immediate without destination.
		return fmt.Errorf("task has no deadline or destination")
	}

	return nil
}

func deleteStateMachineTimersByPath(execInfo *persistencespb.WorkflowExecutionInfo, path []hsm.Key) {
	trimmedTimers := make([]*persistencespb.StateMachineTimerGroup, 0, len(execInfo.StateMachineTimers))

	for _, group := range execInfo.StateMachineTimers {
		trimmedInfos := make([]*persistencespb.StateMachineTaskInfo, 0, len(group.Infos))
		for _, info := range group.GetInfos() {
			if !isPathAffectedByDelete(path, info.GetRef().GetPath()) {
				trimmedInfos = append(trimmedInfos, info)
			}
		}
		if len(trimmedInfos) > 0 {
			trimmedTimers = append(trimmedTimers, &persistencespb.StateMachineTimerGroup{
				Infos:     trimmedInfos,

View on GitHub (pinned to bde624efd1)

Solutions

  1. Give the task a deadline: return a non-nil time.Time from the task's Deadline() (or set TaskInfo.DeadTime) so it is scheduled as a deadline-based task
  2. Give the task a destination: make Destination() return a valid destination string so it is scheduled as a destination-based task
  3. If the task truly must run immediately without destination, do not use this mechanism yet — transfer tasks are unsupported (TODO in task_generator.go); model it as a deadline task with a near-immediate deadline
  4. Upgrade Temporal server if a newer version added transfer-task support for this code path

Example fix

// before (task spec without deadline or destination)
func (t *myTask) Destination() string { return "" }
func (t *myTask) Deadline() time.Time  { return time.Time{} }

// after (deadline-based task)
func (t *myTask) Destination() string { return "" }
func (t *myTask) Deadline() time.Time  { return t.execTime }
Defensive patterns

Strategy: validation

Validate before calling

// Validate the task spec before registering/generating it
func validateTaskSpec(t hsm.Task) error {
	if t.Deadline().IsZero() && t.Destination() == "" {
		return fmt.Errorf("task %T must define a deadline or destination", t)
	}
	return nil
}

Type guard

func hasSchedule(t hsm.Task) bool {
	return !t.Deadline().IsZero() || t.Destination() != ""
}

Prevention

When it happens

Trigger: A dirty sub-state machine is processed (via GenerateDirtySubStateMachineTasks or refreshTasksForSubStateMachines) and the task's Task() implementation returns an empty/nil Deadline and its Destination() returns empty, while Generate() produced taskInfo; generateSubStateMachineTask then hits the else branch and returns this error.

Common situations: Developers adding a new HSM state machine task type that returns a spec with no Deadline and no Destination, or refactoring Task()/Destination() so the deadline is dropped; also seen on upgraded clusters running new custom task definitions against a history service that lacks transfer-task support.

Related errors


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