{"record":{"id":"dd00271a2817ee41","repo":"temporalio/temporal","slug":"invalid-timeout-type","errorCode":null,"errorMessage":"invalid timeout type","messagePattern":"invalid timeout type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/workflow/timer_sequence.go","lineNumber":460,"sourceCode":"\t\tAttempt:      activityInfo.Attempt,\n\t}, true\n}\n\nfunc timerTypeToTimerMask(\n\ttimerType enumspb.TimeoutType,\n) int32 {\n\n\tswitch timerType {\n\tcase enumspb.TIMEOUT_TYPE_START_TO_CLOSE:\n\t\treturn TimerTaskStatusCreatedStartToClose\n\tcase enumspb.TIMEOUT_TYPE_SCHEDULE_TO_START:\n\t\treturn TimerTaskStatusCreatedScheduleToStart\n\tcase enumspb.TIMEOUT_TYPE_SCHEDULE_TO_CLOSE:\n\t\treturn TimerTaskStatusCreatedScheduleToClose\n\tcase enumspb.TIMEOUT_TYPE_HEARTBEAT:\n\t\treturn TimerTaskStatusCreatedHeartbeat\n\tdefault:\n\t\tpanic(\"invalid timeout type\")\n\t}\n}\n\n// Len implements sort.Interface\nfunc (s TimerSequenceIDs) Len() int {\n\treturn len(s)\n}\n\n// Swap implements sort.Interface.\nfunc (s TimerSequenceIDs) Swap(\n\tthis int,\n\tthat int,\n) {\n\ts[this], s[that] = s[that], s[this]\n}\n\n// Less implements sort.Interface\nfunc (s TimerSequenceIDs) Less(","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/workflow/timer_sequence.go#L442-L478","documentation":"timerTypeToTimerMask in service/history/workflow/timer_sequence.go converts a TimeoutType (SCHEDULE_TO_START, SCHEDULE_TO_CLOSE, START_TO_CLOSE, HEARTBEAT) into a TimerTaskStatus bit. The default branch panics with \"invalid timeout type\" when given a timeout type without a mapping — notably TIME_OUT_TYPE_UNSPECIFIED or any newer enum value. Raised inside timerTypeToTimerMask, called by CreateNextActivityTimer and TestConversion, when an activity timer is created for an activity whose TimeoutType field is unset or unrecognized.","triggerScenarios":"CreateNextActivityTimer processing an activity whose persisted TimeoutType is TIME_OUT_TYPE_UNSPECIFIED (zero value) or a TIMEOUT_TYPE added in a newer proto/API version than the running server knows.","commonSituations":"Persistence/API rows written by a newer server with a new TimeoutType then loaded by an older binary; corrupted activity rows where the scheduled event lost its timeout configuration; version-skewed clusters during upgrades.","solutions":["Upgrade the server binary so all proto TIMEOUT_TYPE values are recognized (fix version skew).","Inspect the activity's scheduled event / persisted TimeoutType and repair the workflow or reset it to a point before the corrupted activity.","Ensure the SDK/caller sets an explicit timeout type when scheduling activities (never rely on the UNSPECIFIED zero value).","Report with the workflow/activity IDs if it occurs on consistent versions."],"exampleFix":"// before (server-side mapping)\ncase enumspb.TIMEOUT_TYPE_HEARTBEAT:\n    return TimerTaskStatusCreatedHeartbeat\ndefault:\n    panic(\"invalid timeout type\")\n// after (hardened mapping)\ncase enumspb.TIMEOUT_TYPE_HEARTBEAT:\n    return TimerTaskStatusCreatedHeartbeat\ncase enumspb.TIMEOUT_TYPE_UNSPECIFIED:\n    ms.logger.Warn(\"activity with unspecified timeout type\", ...)\n    return TimerTaskStatusCreatedScheduleToClose","handlingStrategy":"validation","validationCode":"// Application side: always set explicit timeout types when scheduling activities:\nactivityOptions := workflow.ActivityOptions{\n    ScheduleToStartTimeout: 10 * time.Second,\n    StartToCloseTimeout:    30 * time.Second,\n    // Set every timeout you use explicitly; never leave TimeoutType unset.\n}","typeGuard":"func hasValidTimeoutType(t enumspb.TimeoutType) bool {\n    switch t {\n    case enumspb.TIMEOUT_TYPE_SCHEDULE_TO_START,\n        enumspb.TIMEOUT_TYPE_SCHEDULE_TO_CLOSE,\n        enumspb.TIMEOUT_TYPE_START_TO_CLOSE,\n        enumspb.TIMEOUT_TYPE_HEARTBEAT:\n        return true\n    }\n    return false // includes TIMEOUT_TYPE_UNSPECIFIED and newer values\n}","tryCatchPattern":"// The panic happens inside the history service, not the SDK caller; recover via\n// workflow reset rather than catch:\n// temporal --ns <ns> workflow reset --wid <wid> --eid <event-id> --reason \"corrupt activity timeout\"","preventionTips":["Always configure ScheduleToStart/StartToClose/ScheduleToClose timeouts on activities.","Never run older server binaries against data written by newer ones (version skew).","Keep server and SDK proto dependencies compatible when upgrading.","If a panic occurs, reset the affected workflow to before the malformed activity."],"tags":["go","panic","timeout-type","timers","activity"],"backgroundTag":"invalid-timeout-type","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}