{"record":{"id":"da5c25764de4b531","repo":"temporalio/temporal","slug":"can-t-decode-tweakablepolicies","errorCode":null,"errorMessage":"can't decode TweakablePolicies:","messagePattern":"can't decode TweakablePolicies:","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"service/worker/scheduler/workflow.go","lineNumber":1329,"sourceCode":"func (s *scheduler) checkConflict(token int64) error {\n\tif token == 0 || token == s.State.ConflictToken {\n\t\treturn nil\n\t}\n\treturn errUpdateConflict\n}\n\nfunc (s *scheduler) updateTweakables() {\n\t// Use MutableSideEffect so that we can change the defaults without breaking determinism.\n\tget := func(ctx workflow.Context) any {\n\t\tp := CurrentTweakablePolicies\n\t\t// Re-evaluates migration dynamic config each iteration.\n\t\tp.EnableCHASMMigration = s.enableCHASMMigration()\n\t\tp.MigrateWithRunningWorkflows = s.migrateWithRunningWorkflows()\n\t\treturn p\n\t}\n\teq := func(a, b any) bool { return a.(TweakablePolicies) == b.(TweakablePolicies) }\n\tif err := workflow.MutableSideEffect(s.ctx, \"tweakables\", get, eq).Get(&s.tweakables); err != nil {\n\t\tpanic(\"can't decode TweakablePolicies:\" + err.Error())\n\t}\n}\n\nfunc (s *scheduler) getCatchupWindow() time.Duration {\n\tcw := s.Schedule.Policies.CatchupWindow\n\tif cw == nil {\n\t\treturn s.tweakables.DefaultCatchupWindow\n\t} else if cw.AsDuration() < s.tweakables.MinCatchupWindow {\n\t\treturn s.tweakables.MinCatchupWindow\n\t} else {\n\t\treturn cw.AsDuration()\n\t}\n}\n\nfunc (s *scheduler) resolveOverlapPolicy(overlapPolicy enumspb.ScheduleOverlapPolicy) enumspb.ScheduleOverlapPolicy {\n\tif overlapPolicy == enumspb.SCHEDULE_OVERLAP_POLICY_UNSPECIFIED {\n\t\toverlapPolicy = s.Schedule.Policies.OverlapPolicy\n\t}","sourceCodeStart":1311,"sourceCodeEnd":1347,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/worker/scheduler/workflow.go#L1311-L1347","documentation":"TweakablePolicies are captured via workflow.MutableSideEffect so all replayed executions see identical values. If the stored side-effect blob cannot be decoded into TweakablePolicies on replay, the workflow cannot proceed deterministically and panics. This indicates persisted data incompatible with the current struct definition.","triggerScenarios":"Raised in the scheduler workflow's tweakables loading path (service/worker/scheduler/workflow.go:1329) when workflow.MutableSideEffect(...).Get(&s.tweakables) returns a decode error — the stored blob was written by a different schema/version, or the value is corrupted/truncated.","commonSituations":"Upgrading Temporal across a TweakablePolicies struct change with an in-flight schedule; importing/replaying a workflow history produced by a mismatched version; corrupted persistence payload.","solutions":["Run a worker version that matches the one that wrote the side-effect (version pinning / patching)","Terminate and restart the schedule workflow so tweakables are re-captured from current schedule config","Restore the workflow from a history point before the incompatible side-effect write"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deploy worker and server upgrades atomically so side-effect writers and readers match","Use workflow.Patched/version gates when mutating TweakablePolicies fields","Avoid reusing one namespace's schedule workflow history across clusters with different code versions","Test upgrades against a staging schedule with in-flight workflows"],"tags":["panic","workflow-replay","side-effect","decoding"],"backgroundTag":"side-effect-decode-failure","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}