temporalio/temporal · error
history task from queue has nil blob
Error message
history task from queue has nil blob
What it means
ErrHistoryTaskBlobIsNil (common/persistence/history_task_queue_manager.go:42) is returned by ReadTasks when a raw history task read from the queue has a nil Blob. The queue stores tasks as serialized blobs; a nil blob cannot be deserialized, so ReadTasks wraps the failure in a serialization.NewDeserializationError with ENCODING_TYPE_PROTO3. This indicates corrupted or improperly persisted task data in the queue.
Source
Thrown at common/persistence/history_task_queue_manager.go:42
// ErrMsgDeserializeRawHistoryTask is returned when the raw task cannot be deserialized from the task queue. This error
// is returned when this whole top-level proto cannot be deserialized.
// 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,View on GitHub (pinned to bde624efd1)
Solutions
- Delete/skip the corrupt task record and let the task be re-enqueued or regenerated by its producer (history service)
- Inspect the queue's underlying persistence rows to find how many tasks have nil blobs and check recent writer versions
- Upgrade/fix the writer path that persisted tasks without blobs
- Acknowledge the task via ack manager so the poison record does not block the queue's read pointer
Example fix
// producer side: before
queue.EnqueueTask(ctx, &persistence.Task{TaskID: id}) // blob never set
// after
data, err := serializer.SerializeHistoryTask(task)
if err != nil { return err }
queue.EnqueueTask(ctx, &persistence.Task{TaskID: id, Blob: data}) Defensive patterns
Strategy: type-guard
Type guard
func isNilBlobErr(err error) bool {
var de *serialization.DataError
return errors.As(err, &de) && strings.Contains(err.Error(), persistence.ErrHistoryTaskBlobIsNil.Error())
} Try / catch
tasks, err := mgr.ReadTasks(ctx, req)
if err != nil {
if isNilBlobErr(err) {
logger.Error("nil-blob history task encountered; acking to skip poison record", tag.Error(err))
return ackAndSkip(err) // advance past corrupt record
}
return err
} Prevention
- Ensure EnqueueTask always serializes and sets Blob (nil Task is rejected earlier by ErrEnqueueTaskRequestTaskIsNil)
- Test producer code paths for tasks that fail to build (nil task/blob)
- Monitor deserialization-error metrics on history task queues
- Add a storage integrity check for task rows with NULL blob columns
When it happens
Trigger: Calling HistoryTaskQueueManagerImpl.ReadTasks (or ReadRawTasks feeding it) and encountering a queue record whose Blob field is nil, at history_task_queue_manager.go:159.
Common situations: Storage records written by an older/buggy writer version; data corruption in the queue's underlying persistence; manual edits or partial writes to the tasks table; replication issues leaving incomplete task rows.
Related errors
- page size to read history tasks must be positive
- enqueue task request task is nil
- queue already exists
- shard ID must be greater than 0
- invalid queue name, expected 4 fields
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/00a6d009fb6e2bee.
Report an issue: GitHub.