{"record":{"id":"ade4ccf43ff251fb","repo":"temporalio/temporal","slug":"updatetaskqueue-encountered-lastupdatetime-not-set","errorCode":null,"errorMessage":"UpdateTaskQueue encountered LastUpdateTime not set","messagePattern":"UpdateTaskQueue encountered LastUpdateTime not set","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/persistence/task_manager.go","lineNumber":81,"sourceCode":"\t\tTaskType:      request.TaskQueueInfo.GetTaskType(),\n\t\tTaskQueueKind: request.TaskQueueInfo.GetKind(),\n\t\tRangeID:       request.RangeID,\n\t\tExpiryTime:    taskQueueInfo.ExpiryTime,\n\t\tTaskQueueInfo: taskQueueInfoBlob,\n\t}\n\tif err := m.taskStore.CreateTaskQueue(ctx, internalRequest); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &CreateTaskQueueResponse{}, nil\n}\n\nfunc (m *taskManagerImpl) UpdateTaskQueue(\n\tctx context.Context,\n\trequest *UpdateTaskQueueRequest,\n) (*UpdateTaskQueueResponse, error) {\n\ttaskQueueInfo := request.TaskQueueInfo\n\tif taskQueueInfo.LastUpdateTime == nil {\n\t\tpanic(\"UpdateTaskQueue encountered LastUpdateTime not set\")\n\t}\n\tif taskQueueInfo.ExpiryTime == nil && taskQueueInfo.GetKind() == enumspb.TASK_QUEUE_KIND_STICKY {\n\t\tpanic(\"UpdateTaskQueue encountered ExpiryTime not set for sticky task queue\")\n\t}\n\ttaskQueueInfoBlob, err := m.serializer.TaskQueueInfoToBlob(taskQueueInfo)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tinternalRequest := &InternalUpdateTaskQueueRequest{\n\t\tNamespaceID:   request.TaskQueueInfo.GetNamespaceId(),\n\t\tTaskQueue:     request.TaskQueueInfo.GetName(),\n\t\tTaskType:      request.TaskQueueInfo.GetTaskType(),\n\t\tRangeID:       request.RangeID,\n\t\tTaskQueueInfo: taskQueueInfoBlob,\n\n\t\tTaskQueueKind: request.TaskQueueInfo.GetKind(),\n\t\tExpiryTime:    taskQueueInfo.ExpiryTime,","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/task_manager.go#L63-L99","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\n_, err := taskManager.UpdateTaskQueue(ctx, &persistence.UpdateTaskQueueRequest{\n    TaskQueueInfo: taskQueueInfo, // LastUpdateTime nil\n})\n// after\ntaskQueueInfo.LastUpdateTime = timestamp.TimePtr(time.Now().UTC())\n_, err := taskManager.UpdateTaskQueue(ctx, &persistence.UpdateTaskQueueRequest{\n    TaskQueueInfo: taskQueueInfo,\n})","handlingStrategy":"validation","validationCode":"func validateTQLastUpdate(tq *persistencespb.TaskQueueInfo) error {\n    if tq.LastUpdateTime == nil {\n        return fmt.Errorf(\"task queue %q requires LastUpdateTime\", tq.GetName())\n    }\n    return nil\n}","typeGuard":"func hasLastUpdateTime(tq *persistencespb.TaskQueueInfo) bool { return tq.GetLastUpdateTime() != nil && !tq.GetLastUpdateTime().AsTime().IsZero() }","tryCatchPattern":"// validate before the persistence call; do not rely on recover\nif err := validateTQLastUpdate(tqInfo); err != nil { return nil, err }\n_, err := mgr.UpdateTaskQueue(ctx, &persistence.UpdateTaskQueueRequest{TaskQueueInfo: tqInfo})","preventionTips":["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"],"tags":["persistence","panic","task-queue","lastupdatetime"],"backgroundTag":"task-queue-lastupdatetime-not-set","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}