temporalio/temporal · error

Reset point for %v is expired

Error message

Reset point for %v is expired

What it means

getResetPoint rejects an auto-reset point whose ExpireTime has passed. Auto-reset points carry an expiry so that old deployment versions cannot be reset to after a retention window; once expired the point is no longer valid for reset and this error is returned.

Source

Thrown at service/worker/batcher/activities.go:1175

	execution *commonpb.WorkflowExecution,
	frontendClient workflowservice.WorkflowServiceClient,
	buildId string,
	currentRunOnly bool,
) (workflowTaskEventID int64, err error) {
	res, err := frontendClient.DescribeWorkflowExecution(ctx, &workflowservice.DescribeWorkflowExecutionRequest{
		Namespace: namespaceStr,
		Execution: execution,
	})
	if err != nil {
		return 0, err
	}
	resetPoints := res.GetWorkflowExecutionInfo().GetAutoResetPoints().GetPoints()
	for _, point := range resetPoints {
		if point.BuildId == buildId {
			if !point.Resettable {
				return 0, fmt.Errorf("Reset point for %v is not resettable", buildId)
			} else if point.ExpireTime != nil && point.ExpireTime.AsTime().Before(time.Now()) {
				return 0, fmt.Errorf("Reset point for %v is expired", buildId)
			} else if execution.RunId != point.RunId && currentRunOnly {
				return 0, fmt.Errorf("Reset point for %v points to previous run and CurrentRunOnly is set", buildId)
			}
			execution.RunId = point.RunId
			return point.FirstWorkflowTaskCompletedId, nil
		}
	}
	return 0, fmt.Errorf("Can't find reset point for %v", buildId)
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Act on resets promptly before the point expires; re-run the reset as soon as the bad deployment is identified.
  2. Choose a non-expired reset point: enumerate auto-reset points and filter by ExpireTime in the future before selecting.
  3. If resets are needed long-term, rely on workflow restart/continue-as-new or archive-based recovery instead of expired reset points.
  4. Adjust server-side reset-point expiry configuration if your operational runbooks require a longer window.

Example fix

// before
resetID, err := getResetEventIDByOptions(ctx, exec, &ResetOptions{BuildId: "v1"}) // expired
// after
points := info.GetAutoResetPoints().GetPoints()
for _, p := range points {
  if p.GetBuildId() == "v1" && (p.GetExpireTime() == nil || p.GetExpireTime().AsTime().After(time.Now())) {
    resetID, err = getResetEventIDByOptions(ctx, exec, &ResetOptions{BuildId: p.GetBuildId()})
    break
  }
}
Defensive patterns

Strategy: validation

Validate before calling

points := info.GetAutoResetPoints().GetPoints()
for _, p := range points {
  if p.GetBuildId() == buildId {
    if p.GetExpireTime() != nil && p.GetExpireTime().AsTime().Before(time.Now()) {
      return fmt.Errorf("reset point for %s expired at %s", buildId, p.GetExpireTime().AsTime())
    }
  }
}

Type guard

func isExpired(p *deploymentpb.ResetPoint, now time.Time) bool {
  return p.GetExpireTime() != nil && p.GetExpireTime().AsTime().Before(now)
}

Try / catch

if err := doReset(ctx, exec, buildId); err != nil {
  if strings.Contains(err.Error(), "is expired") {
    return resetToNonExpiredPoint(ctx, exec)
  }
  return err
}

Prevention

When it happens

Trigger: Calling getResetEventIDByOptions with a buildId whose auto-reset point has ExpireTime set and point.ExpireTime.AsTime().Before(time.Now()) — i.e. the reset request arrives after the point's expiration timestamp.

Common situations: Delayed/incident-response reset attempts days after the bad deployment; batch jobs replaying old reset inputs; deployments where reset points expire quickly per server configuration, so automation using cached buildIds fails.

Related errors


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