{"record":{"id":"14c6fb251ecb5fc7","repo":"temporalio/temporal","slug":"shard-id-must-be-greater-than-0","errorCode":null,"errorMessage":"shard ID must be greater than 0","messagePattern":"shard ID must be greater than 0","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/persistence/history_task_queue_manager.go","lineNumber":45,"sourceCode":"\t//\t- ShardID\n\t//\t- Blob (a serialized task)\n\tErrMsgDeserializeRawHistoryTask = \"failed to deserialize raw history task from task queue\"\n\t// ErrMsgDeserializeHistoryTask is returned when the history task cannot be deserialized from the task queue. This\n\t// error is returned when the blob inside the raw task cannot be deserialized.\n\t//  Raw Task (a proto):\n\t//\t- ShardID\n\t//\t- Blob (a serialized task) <-- when this cannot be deserialized\n\tErrMsgDeserializeHistoryTask = \"failed to deserialize history task blob\"\n\t// ErrMsgFailedToParseCategoryID is returned when category id cannot be parsed as an integer value.\n\tErrMsgFailedToParseCategoryID = \"failed to parse category id from queue name\"\n)\n\nvar (\n\tErrReadTasksNonPositivePageSize = errors.New(\"page size to read history tasks must be positive\")\n\tErrHistoryTaskBlobIsNil         = errors.New(\"history task from queue has nil blob\")\n\tErrEnqueueTaskRequestTaskIsNil  = errors.New(\"enqueue task request task is nil\")\n\tErrQueueAlreadyExists           = errors.New(\"queue already exists\")\n\tErrShardIDInvalid               = errors.New(\"shard ID must be greater than 0\")\n\tErrInvalidQueueName             = errors.New(\"invalid queue name, expected 4 fields\")\n)\n\nfunc NewHistoryTaskQueueManager(\n\tqueue QueueV2,\n\tserializer serialization.Serializer,\n) *HistoryTaskQueueManagerImpl {\n\treturn &HistoryTaskQueueManagerImpl{\n\t\tqueue:      queue,\n\t\tserializer: serializer,\n\t}\n}\n\nfunc (m *HistoryTaskQueueManagerImpl) EnqueueTask(\n\tctx context.Context,\n\trequest *EnqueueTaskRequest,\n) (*EnqueueTaskResponse, error) {\n\tif request.Task == nil {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/history_task_queue_manager.go#L27-L63","documentation":"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.","triggerScenarios":"Calling EnqueueTask with request.ShardID <= 0 (typically 0 from an uninitialized request struct).","commonSituations":"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.","solutions":["Populate ShardID from the shard context (e.g. shardContext.GetShardID()) before enqueueing","Add an early validation/log at the producer when shard ID is unavailable","Fix any 0-based/1-based indexing mismatch in code computing shard IDs"],"exampleFix":"// before\nmgr.EnqueueTask(ctx, &persistence.EnqueueTaskRequest{ShardID: shardIDFromUnsetStruct}) // 0\n// after\nif shardID <= 0 {\n    return fmt.Errorf(\"invalid shard ID %d for history task enqueue\", shardID)\n}\nmgr.EnqueueTask(ctx, &persistence.EnqueueTaskRequest{ShardID: shardID, Task: task})","handlingStrategy":"validation","validationCode":"if req.ShardID <= 0 {\n    return fmt.Errorf(\"shard ID must be > 0, got %d\", req.ShardID)\n}\n// safe to call EnqueueTask","typeGuard":null,"tryCatchPattern":"err := mgr.EnqueueTask(ctx, req)\nif err != nil {\n    if errors.Is(err, persistence.ErrShardIDInvalid) {\n        logger.Error(\"invalid shard ID in enqueue request\", tag.ShardID(req.ShardID))\n        return err // programmer error: do not retry\n    }\n    return err\n}","preventionTips":["Obtain shard IDs from shardContext.GetShardID(), never hardcode 0","Remember history queue shard IDs are 1-based","Validate shard ID at request construction, not at the persistence boundary","Cover the zero-value request struct case in producer unit tests"],"tags":["go","persistence","task-queue","invalid-argument","shard-id"],"backgroundTag":"invalid-argument","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}