temporalio/temporal · warning
queue already exists
Error message
queue already exists
What it means
ErrQueueAlreadyExists (common/persistence/history_task_queue_manager.go:44) is returned by CreateQueue and WriteTaskToDLQ when a queue with the same identity (category + shard ID) already exists in persistence. Queue creation is expected to be idempotent-exclusive: creating a duplicate queue name is rejected rather than silently reusing it. This is often benign during concurrent startup, where several history shards race to create the same queue.
Solutions
- Treat errors.Is(err, ErrQueueAlreadyExists) as success in creation paths and proceed to use the existing queue
- Add a unique-constraint/exists check before CreateQueue, or use a create-if-not-exists API if available
- For WriteTaskToDLQ, ensure the DLQ is created once and reused rather than re-created per write
Example fix
// before
if err := mgr.CreateQueue(ctx, req); err != nil {
return err // fails on restart/concurrent startup
}
// after
if err := mgr.CreateQueue(ctx, req); err != nil && !errors.Is(err, persistence.ErrQueueAlreadyExists) {
return err
} // queue already present: reuse it Defensive patterns
Strategy: type-guard
Type guard
func isQueueAlreadyExists(err error) bool {
return errors.Is(err, persistence.ErrQueueAlreadyExists)
} Try / catch
err := mgr.CreateQueue(ctx, req)
if err != nil && !errors.Is(err, persistence.ErrQueueAlreadyExists) {
return err // real failure; duplicate creation is benign
}
// proceed using the existing queue Prevention
- Always treat ErrQueueAlreadyExists as success in idempotent bootstrap/startup code
- Serialize queue creation through a single initializer or use create-if-not-exists semantics
- For DLQs, create once and reuse; never re-create per write
- In tests, clean up queues between cases or tolerate the duplicate sentinel
When it happens
Trigger: Calling CreateQueue for a (category, shardID) pair already present in the queue persistence; WriteTaskToDLQ when the DLQ for that queue already exists and the store does not support writing to an existing DLQ implicitly.
Common situations: Concurrent history-shard startup where multiple instances race to create the same queue; re-running initialization/bootstrap code without idempotency handling; attempting to write to a DLQ that was already created by a previous run.
Related errors
- enqueue task request task is nil
- history task from queue has nil blob
- invalid queue name, expected 4 fields
- page size to read history tasks must be positive
- shard ID must be greater than 0
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/d8267b73cbfc2b42.
Report an issue: GitHub.
Appendix: source
Thrown at common/persistence/history_task_queue_manager.go:44
// 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,
) (*EnqueueTaskResponse, error) {View on GitHub (pinned to bde624efd1)