temporalio/temporal · error
UpdateTaskQueue encountered LastUpdateTime not set
Error message
UpdateTaskQueue encountered LastUpdateTime not set
What it means
UpdateTaskQueue in the persistence task manager panics when TaskQueueInfo.LastUpdateTime is nil. LastUpdateTime is used by the persistence layer for optimistic staleness checks and by matching/history to ignore out-of-order task queue updates, so its absence is an unrecoverable caller bug and the manager intentionally panics rather than persisting an update with no ordering information.
Source
Thrown at common/persistence/task_manager.go:81
TaskType: request.TaskQueueInfo.GetTaskType(),
TaskQueueKind: request.TaskQueueInfo.GetKind(),
RangeID: request.RangeID,
ExpiryTime: taskQueueInfo.ExpiryTime,
TaskQueueInfo: taskQueueInfoBlob,
}
if err := m.taskStore.CreateTaskQueue(ctx, internalRequest); err != nil {
return nil, err
}
return &CreateTaskQueueResponse{}, nil
}
func (m *taskManagerImpl) UpdateTaskQueue(
ctx context.Context,
request *UpdateTaskQueueRequest,
) (*UpdateTaskQueueResponse, error) {
taskQueueInfo := request.TaskQueueInfo
if taskQueueInfo.LastUpdateTime == nil {
panic("UpdateTaskQueue encountered LastUpdateTime not set")
}
if taskQueueInfo.ExpiryTime == nil && taskQueueInfo.GetKind() == enumspb.TASK_QUEUE_KIND_STICKY {
panic("UpdateTaskQueue encountered ExpiryTime not set for sticky task queue")
}
taskQueueInfoBlob, err := m.serializer.TaskQueueInfoToBlob(taskQueueInfo)
if err != nil {
return nil, err
}
internalRequest := &InternalUpdateTaskQueueRequest{
NamespaceID: request.TaskQueueInfo.GetNamespaceId(),
TaskQueue: request.TaskQueueInfo.GetName(),
TaskType: request.TaskQueueInfo.GetTaskType(),
RangeID: request.RangeID,
TaskQueueInfo: taskQueueInfoBlob,
TaskQueueKind: request.TaskQueueInfo.GetKind(),
ExpiryTime: taskQueueInfo.ExpiryTime,View on GitHub (pinned to bde624efd1)
Solutions
- Always set LastUpdateTime to time.Now().UTC() (wrapped with timestamp.TimePtr) immediately before building UpdateTaskQueueRequest.
- When carrying forward an existing TaskQueueInfo, refresh LastUpdateTime instead of reusing the stale/nil value from the loaded blob.
- If the info comes from deserialized storage, normalize nil LastUpdateTime to the current time after loading.
- Add a pre-send assertion in the calling service (matching/frontend) that LastUpdateTime is non-nil.
Example fix
// before
_, err := taskManager.UpdateTaskQueue(ctx, &persistence.UpdateTaskQueueRequest{
TaskQueueInfo: taskQueueInfo, // LastUpdateTime nil
})
// after
taskQueueInfo.LastUpdateTime = timestamp.TimePtr(time.Now().UTC())
_, err := taskManager.UpdateTaskQueue(ctx, &persistence.UpdateTaskQueueRequest{
TaskQueueInfo: taskQueueInfo,
}) Defensive patterns
Strategy: validation
Validate before calling
func validateTQLastUpdate(tq *persistencespb.TaskQueueInfo) error {
if tq.LastUpdateTime == nil {
return fmt.Errorf("task queue %q requires LastUpdateTime", tq.GetName())
}
return nil
} Type guard
func hasLastUpdateTime(tq *persistencespb.TaskQueueInfo) bool { return tq.GetLastUpdateTime() != nil && !tq.GetLastUpdateTime().AsTime().IsZero() } Try / catch
// validate before the persistence call; do not rely on recover
if err := validateTQLastUpdate(tqInfo); err != nil { return nil, err }
_, err := mgr.UpdateTaskQueue(ctx, &persistence.UpdateTaskQueueRequest{TaskQueueInfo: tqInfo}) Prevention
- Stamp LastUpdateTime = timestamp.TimePtr(time.Now().UTC()) at request build time, not earlier
- Normalize nil LastUpdateTime after deserializing task queue blobs
- Lint/review rule: any UpdateTaskQueueRequest literal must set LastUpdateTime
When it happens
Trigger: Calling PersistenceManager.UpdateTaskQueue with request.TaskQueueInfo.LastUpdateTime == nil (the sticky-kind ExpiryTime panic at line 84 fires only after this one, so a nil LastUpdateTime masks it).
Common situations: Constructing UpdateTaskQueueRequest by hand in tests or CLI tools; a new code path that copies TaskQueueInfo from an older proto message predating the LastUpdateTime field; decoding old persisted blobs that lack LastUpdateTime and reusing them for update.
Related errors
- CreateTaskQueue encountered ExpiryTime not set for sticky ta
- UpdateTaskQueue encountered ExpiryTime not set for sticky ta
- unsupported partition kind:
- page size to read history tasks must be positive
- history task from queue has nil blob
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/ade4ccf43ff251fb.
Report an issue: GitHub.