temporalio/temporal · critical
GetActivityTaskScheduledEventAttributes is not set
Error message
GetActivityTaskScheduledEventAttributes is not set
What it means
matching_engine.go converts a history-service RecordActivityTaskStartedResponse into a PollActivityTaskQueueResponse. It expects ScheduledEvent to carry ActivityTaskScheduledEventAttributes; if the oneof is nil the event is the wrong type or corrupt, so the code panics rather than emitting a malformed task to a worker.
Source
Thrown at service/matching/matching_engine.go:3385
StartedTime: resp.StartedTime,
Queries: resp.Queries,
Messages: resp.Messages,
History: history,
NextPageToken: resp.NextPageToken,
PollerScalingDecision: resp.PollerScalingDecision,
}
return newResp, nil
}
// Populate the activity task response based on context and scheduled/started events.
func (e *matchingEngineImpl) createPollActivityTaskQueueResponse(
task *internalTask,
historyResponse *historyservice.RecordActivityTaskStartedResponse,
metricsHandler metrics.Handler,
) *matchingservice.PollActivityTaskQueueResponse {
scheduledEvent := historyResponse.ScheduledEvent
if scheduledEvent.GetActivityTaskScheduledEventAttributes() == nil {
panic("GetActivityTaskScheduledEventAttributes is not set")
}
attributes := scheduledEvent.GetActivityTaskScheduledEventAttributes()
if attributes.ActivityId == "" {
panic("ActivityTaskScheduledEventAttributes.ActivityID is not set")
}
if task.responseC == nil {
ct := timestamp.TimeValue(task.event.Data.CreateTime)
metrics.AsyncMatchLatencyPerTaskQueue.With(metricsHandler).Record(time.Since(ct))
}
componentRef := task.event.GetData().GetComponentRef()
activityAttemptStamp := int32(0)
if len(componentRef) > 0 {
activityAttemptStamp = task.event.Data.GetStamp()
}
taskToken := tasktoken.NewActivityTaskToken(
task.event.Data.GetNamespaceId(),View on GitHub (pinned to bde624efd1)
Solutions
- Inspect the history event for the affected workflow/run to confirm the scheduled event is of type ActivityTaskScheduledEventAttributes
- Check for history/matching version skew and upgrade the services to consistent versions
- Fix test fixtures or mock history responses to set ScheduledEvent with ActivityTaskScheduledEventAttributes
- If corruption is confirmed, fail the affected task and let the workflow retry schedule a fresh activity
Example fix
// before (test/mock)
resp := &historyservice.RecordActivityTaskStartedResponse{
ScheduledEvent: &historypb.HistoryEvent{EventType: historypb.EVENT_TYPE_ACTIVITY_TASK_SCHEDULED},
}
// after
resp := &historyservice.RecordActivityTaskStartedResponse{
ScheduledEvent: &historypb.HistoryEvent{
EventType: historypb.EVENT_TYPE_ACTIVITY_TASK_SCHEDULED,
Attributes: &historypb.HistoryEvent_ActivityTaskScheduledEventAttributes{
ActivityTaskScheduledEventAttributes: &historypb.ActivityTaskScheduledEventAttributes{
ActivityId: "activity-1",
},
},
},
} Defensive patterns
Strategy: type-guard
Validate before calling
if resp.GetScheduledEvent().GetActivityTaskScheduledEventAttributes() == nil {
return fmt.Errorf("scheduled event missing ActivityTaskScheduledEventAttributes")
} Type guard
func hasActivityScheduledAttrs(ev *historypb.HistoryEvent) bool {
return ev.GetActivityTaskScheduledEventAttributes() != nil
} Try / catch
func safeBuildResponse(resp *historyservice.RecordActivityTaskStartedResponse) (r *matchingservice.PollActivityTaskQueueResponse, err error) {
defer func() {
if rec := recover(); rec != nil {
err = fmt.Errorf("invalid scheduled event: %v", rec)
}
}()
return newPollActivityTaskQueueResponse(task, resp, mh)
} Prevention
- In tests, use proto builders/helpers that always set full scheduled event attributes rather than hand-rolled HistoryEvent structs
- Keep history and matching services on compatible versions to avoid event schema skew
- Add assertions in test fixtures verifying event oneof type before calling matching conversion code
When it happens
Trigger: RecordActivityTaskStarted returns a scheduled event whose type is not ActivityTaskScheduledEvent (e.g. wrong event type persisted, history returning a corrupted or truncated event), or a nil ScheduledEvent passed to newPollActivityTaskQueueResponse.
Common situations: Data corruption or version-skew between history and matching services where event encoding changed; custom persistence/visibility migrations producing wrong event types; tests feeding hand-built history responses missing ScheduledEvent.
Related errors
- ActivityTaskScheduledEventAttributes.ActivityID is not set
- Current cluster name is empty
- Version increment <= 0 or > 2147483647
- <dynamic updateVersionToClusterName err>
- Current cluster is not specified in cluster info
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/fdf5b509b4834d37.
Report an issue: GitHub.