temporalio/temporal · error

unknown task status: %v

Error message

unknown task status: %v

What it means

The scanner's fixed-pool executor panics when a submitted task reports a status value the executor's result switch doesn't recognize. TaskStatus is an internal enum; this panic guards against a new status being added without updating the executor loop.

Source

Thrown at service/worker/scanner/executor/executor.go:137

		status := task.Run()
		switch status {
		case TaskStatusDone:
			e.outstanding.Add(-1)
			metrics.ExecutorTasksDoneCount.With(e.metricsHandler).Record(1)
		case TaskStatusDefer:
			if e.runQ.deferredCount() < e.maxDeferred {
				e.runQ.addAndDefer(task)
				metrics.ExecutorTasksDeferredCount.With(e.metricsHandler).Record(1)
			} else {
				e.outstanding.Add(-1)
				metrics.ExecutorTasksDroppedCount.With(e.metricsHandler).Record(1)
			}
		case TaskStatusErr:
			e.outstanding.Add(-1)
			metrics.ExecutorTasksErrCount.With(e.metricsHandler).Record(1)
		default:
			panic(fmt.Sprintf("unknown task status: %v", status))
		}
	}
}

func (e *fixedPoolExecutor) alive() bool {
	return e.status.Load() == common.DaemonStatusStarted
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Add a case for the unexpected status in the executor's result switch
  2. Ensure all scanner task implementations return only statuses handled by the executor
  3. Roll back or align task/executor code versions if a partial deploy introduced the new status

Example fix

// before
case TaskStatusErr:
    e.outstanding.Add(-1)
    metrics.ExecutorTasksErrCount.With(e.metricsHandler).Record(1)
default:
    panic(fmt.Sprintf("unknown task status: %v", status))
// after
case TaskStatusErr:
    e.outstanding.Add(-1)
    metrics.ExecutorTasksErrCount.With(e.metricsHandler).Record(1)
case TaskStatusTimeout: // newly added status
    e.outstanding.Add(-1)
    metrics.ExecutorTasksErrCount.With(e.metricsHandler).Record(1)
default:
    e.logger.Error("unknown task status", tag.Status(int(status)))
    e.outstanding.Add(-1)
Defensive patterns

Strategy: type-guard

Type guard

func isHandledStatus(s TaskStatus) bool {
    switch s {
    case TaskStatusCompleted, TaskStatusErr, TaskStatusPending:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Raised in the worker loop of fixedPoolExecutor (service/worker/scanner/executor/executor.go:137) when a task's result status is not TaskStatusCompleted, TaskStatusErr, or the other handled values — typically after code changes introduce a new TaskStatus variant not wired into the executor.

Common situations: A developer adds a new task status (e.g. a 'skipped' or 'timeout' status) to the scanner tasks but forgets the executor's switch; mixing versions of task implementations with an older executor.

Related errors


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