{"record":{"id":"817691c078e70773","repo":"temporalio/temporal","slug":"reset-point-for-v-is-not-resettable","errorCode":null,"errorMessage":"Reset point for %v is not resettable","messagePattern":"Reset point for (.+?) is not resettable","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/worker/batcher/activities.go","lineNumber":1173,"sourceCode":"\tctx context.Context,\n\tnamespaceStr string,\n\texecution *commonpb.WorkflowExecution,\n\tfrontendClient workflowservice.WorkflowServiceClient,\n\tbuildId string,\n\tcurrentRunOnly bool,\n) (workflowTaskEventID int64, err error) {\n\tres, err := frontendClient.DescribeWorkflowExecution(ctx, &workflowservice.DescribeWorkflowExecutionRequest{\n\t\tNamespace: namespaceStr,\n\t\tExecution: execution,\n\t})\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tresetPoints := res.GetWorkflowExecutionInfo().GetAutoResetPoints().GetPoints()\n\tfor _, point := range resetPoints {\n\t\tif point.BuildId == buildId {\n\t\t\tif !point.Resettable {\n\t\t\t\treturn 0, fmt.Errorf(\"Reset point for %v is not resettable\", buildId)\n\t\t\t} else if point.ExpireTime != nil && point.ExpireTime.AsTime().Before(time.Now()) {\n\t\t\t\treturn 0, fmt.Errorf(\"Reset point for %v is expired\", buildId)\n\t\t\t} else if execution.RunId != point.RunId && currentRunOnly {\n\t\t\t\treturn 0, fmt.Errorf(\"Reset point for %v points to previous run and CurrentRunOnly is set\", buildId)\n\t\t\t}\n\t\t\texecution.RunId = point.RunId\n\t\t\treturn point.FirstWorkflowTaskCompletedId, nil\n\t\t}\n\t}\n\treturn 0, fmt.Errorf(\"Can't find reset point for %v\", buildId)\n}\n","sourceCodeStart":1155,"sourceCodeEnd":1185,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/worker/batcher/activities.go#L1155-L1185","documentation":"getResetPoint looks up an auto-reset point by BuildId in the workflow execution's auto-reset points. If the matching point exists but its Resettable flag is false, the reset is refused with this error because Temporal marks bad deployments as non-resettable to prevent resetting into a known-broken state.","triggerScenarios":"Calling a reset batch operation (via getResetEventIDByOptions -> getResetPoint) with a buildId whose corresponding auto-reset point has Resettable=false — typically because a workflow task failure was recorded as unresettable for that deployment version.","commonSituations":"Attempting to roll back a bad worker deployment after Temporal already flagged that BuildId as not resettable (e.g. the bad version continued to run and was marked by the reset/patching machinery); using the wrong BuildId string for the version you meant to reset.","solutions":["Pick a different, resettable BuildId: list the workflow's auto-reset points and choose an earlier version with Resettable=true.","If the non-resettable point is the one you need, reset to the previous resettable point instead, or use a full workflow termination/restart strategy.","Verify the BuildId string is correct (typo or stale version id leads to unexpected point selection).","Enable the auto-reset-points visibility/config so future bad deployments are recorded resettable before expiry."],"exampleFix":"// before\nresp, _ := client.ResetWorkflow(ctx, &workflowservice.ResetWorkflowExecutionRequest{\n  WorkflowExecution: exec,\n  BuildId: \"bad-deploy-v2\", // marked non-resettable\n})\n// after\nresp, _ := client.DescribeWorkflowExecution(ctx, &workflowservice.DescribeWorkflowExecutionRequest{WorkflowExecution: exec})\nfor _, p := range resp.GetWorkflowExecutionInfo().GetAutoResetPoints().GetPoints() {\n  if p.GetResettable() {\n    _, _ = client.ResetWorkflow(ctx, &workflowservice.ResetWorkflowExecutionRequest{WorkflowExecution: exec, BuildId: p.GetBuildId()})\n    break\n  }\n}","handlingStrategy":"validation","validationCode":"resp, err := client.DescribeWorkflowExecution(ctx, &workflowservice.DescribeWorkflowExecutionRequest{WorkflowExecution: exec})\nif err != nil { return err }\nfor _, p := range resp.GetWorkflowExecutionInfo().GetAutoResetPoints().GetPoints() {\n  if p.GetBuildId() == buildId {\n    if !p.GetResettable() {\n      return fmt.Errorf(\"build %s not resettable; choose another point\", buildId)\n    }\n  }\n}","typeGuard":"func isResettable(points []*deploymentpb.ResetPoint, buildId string) bool {\n  for _, p := range points {\n    if p.GetBuildId() == buildId {\n      return p.GetResettable()\n    }\n  }\n  return false\n}","tryCatchPattern":"if err := doReset(ctx, exec, buildId); err != nil {\n  if strings.Contains(err.Error(), \"is not resettable\") {\n    // fall back to first resettable point\n    return resetToFirstResettablePoint(ctx, exec)\n  }\n  return err\n}","preventionTips":["Always list auto-reset points and check Resettable before issuing a reset.","Prefer the most recent resettable point when rolling back bad deployments.","Don't hardcode BuildIds; fetch them from DescribeWorkflowExecution.","Alert on workflows that mark points non-resettable to catch bad-deploy patterns early."],"tags":["go","reset","worker-versioning","batch"],"backgroundTag":"reset-point-not-resettable","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}