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

  1. Inspect the history event for the affected workflow/run to confirm the scheduled event is of type ActivityTaskScheduledEventAttributes
  2. Check for history/matching version skew and upgrade the services to consistent versions
  3. Fix test fixtures or mock history responses to set ScheduledEvent with ActivityTaskScheduledEventAttributes
  4. 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

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


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