temporalio/temporal · error

shard ID must be greater than 0

Error message

shard ID must be greater than 0

What it means

ErrShardIDInvalid (common/persistence/history_task_queue_manager.go:45) states 'shard ID must be greater than 0'. Shard IDs in the history task queue system are 1-based; a zero or negative shard ID cannot map to a queue partition. EnqueueTask (and the queue Invoke path) validates this before touching persistence, and TestHistoryTaskQueueManager_InvalidShardID covers the guard.

Source

Thrown at common/persistence/history_task_queue_manager.go:45

	//	- 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) {
	if request.Task == nil {

View on GitHub (pinned to bde624efd1)

Solutions

  1. Populate ShardID from the shard context (e.g. shardContext.GetShardID()) before enqueueing
  2. Add an early validation/log at the producer when shard ID is unavailable
  3. Fix any 0-based/1-based indexing mismatch in code computing shard IDs

Example fix

// before
mgr.EnqueueTask(ctx, &persistence.EnqueueTaskRequest{ShardID: shardIDFromUnsetStruct}) // 0
// after
if shardID <= 0 {
    return fmt.Errorf("invalid shard ID %d for history task enqueue", shardID)
}
mgr.EnqueueTask(ctx, &persistence.EnqueueTaskRequest{ShardID: shardID, Task: task})
Defensive patterns

Strategy: validation

Validate before calling

if req.ShardID <= 0 {
    return fmt.Errorf("shard ID must be > 0, got %d", req.ShardID)
}
// safe to call EnqueueTask

Try / catch

err := mgr.EnqueueTask(ctx, req)
if err != nil {
    if errors.Is(err, persistence.ErrShardIDInvalid) {
        logger.Error("invalid shard ID in enqueue request", tag.ShardID(req.ShardID))
        return err // programmer error: do not retry
    }
    return err
}

Prevention

When it happens

Trigger: Calling EnqueueTask with request.ShardID <= 0 (typically 0 from an uninitialized request struct).

Common situations: Zero-value request structs; shard ID loaded from config that failed to initialize; off-by-one or 0-based indexing assumptions by new callers; task forwarding logic that lost the shard ID.

Understand the failure class

Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.

Related errors


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