temporalio/temporal · error

enqueue task request task is nil

Error message

enqueue task request task is nil

What it means

ErrEnqueueTaskRequestTaskIsNil (common/persistence/history_task_queue_manager.go:43) is returned by EnqueueTask when the request carries a nil Task pointer. The manager cannot serialize a nil task into a queue blob, so the enqueue is rejected up front as an invalid argument. It is a programmer-error guard preventing nil records from ever entering the task queue (which would later trip ErrHistoryTaskBlobIsNil on reads).

Source

Thrown at common/persistence/history_task_queue_manager.go:43

	// is returned when this whole top-level proto cannot be deserialized.
	//  Raw Task (a proto): <-- when this cannot be deserialized
	//	- ShardID
	//	- Blob (a serialized task)
	ErrMsgDeserializeRawHistoryTask = "failed to deserialize raw history task from task queue"
	// ErrMsgDeserializeHistoryTask is returned when the history task cannot be deserialized from the task queue. This
	// error is returned when the blob inside the raw task cannot be deserialized.
	//  Raw Task (a proto):
	//	- ShardID
	//	- Blob (a serialized task) <-- when this cannot be deserialized
	ErrMsgDeserializeHistoryTask = "failed to deserialize history task blob"
	// ErrMsgFailedToParseCategoryID is returned when category id cannot be parsed as an integer value.
	ErrMsgFailedToParseCategoryID = "failed to parse category id from queue name"
)

var (
	ErrReadTasksNonPositivePageSize = errors.New("page size to read history tasks must be positive")
	ErrHistoryTaskBlobIsNil         = errors.New("history task from queue has nil blob")
	ErrEnqueueTaskRequestTaskIsNil  = errors.New("enqueue task request task is nil")
	ErrQueueAlreadyExists           = errors.New("queue already exists")
	ErrShardIDInvalid               = errors.New("shard ID must be greater than 0")
	ErrInvalidQueueName             = errors.New("invalid queue name, expected 4 fields")
)

func NewHistoryTaskQueueManager(
	queue QueueV2,
	serializer serialization.Serializer,
) *HistoryTaskQueueManagerImpl {
	return &HistoryTaskQueueManagerImpl{
		queue:      queue,
		serializer: serializer,
	}
}

func (m *HistoryTaskQueueManagerImpl) EnqueueTask(
	ctx context.Context,
	request *EnqueueTaskRequest,

View on GitHub (pinned to bde624efd1)

Solutions

  1. Ensure the Task field is populated before calling EnqueueTask
  2. Add an upstream nil check so nil tasks are rejected/logged at the producer
  3. Fix the task-construction code path that produced a nil task

Example fix

// before
mgr.EnqueueTask(ctx, &persistence.EnqueueTaskRequest{QueueType: category, ShardID: shardID}) // Task missing
// after
task := buildHistoryTask(...)
if task == nil {
    return errors.New("cannot enqueue nil history task")
}
mgr.EnqueueTask(ctx, &persistence.EnqueueTaskRequest{ShardID: shardID, Task: task})
Defensive patterns

Strategy: validation

Validate before calling

if req == nil || req.Task == nil {
    return errors.New("EnqueueTaskRequest.Task must be non-nil")
}
// safe to call EnqueueTask

Type guard

func taskIsEnqueueable(req *persistence.EnqueueTaskRequest) bool {
    return req != nil && req.Task != nil && req.ShardID > 0
}

Try / catch

err := mgr.EnqueueTask(ctx, req)
if err != nil {
    if strings.Contains(err.Error(), "enqueue task request task is nil") {
        logger.Error("nil task refused by queue manager", tag.Error(err))
        return err // programmer error: do not retry
    }
    return err
}

Prevention

When it happens

Trigger: Calling HistoryTaskQueueManagerImpl.EnqueueTask with &persistence.EnqueueTaskRequest{Task: nil} or a zero-value request struct.

Common situations: Constructing the request without populating Task; a nil task flowing from an upstream producer after a failed task build; test scaffolding forgetting to set the field.

Related errors


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