temporalio/temporal · error
invalid timeout type
Error message
invalid timeout type
What it means
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.
Source
Thrown at service/history/workflow/timer_sequence.go:460
Attempt: activityInfo.Attempt,
}, true
}
func timerTypeToTimerMask(
timerType enumspb.TimeoutType,
) int32 {
switch timerType {
case enumspb.TIMEOUT_TYPE_START_TO_CLOSE:
return TimerTaskStatusCreatedStartToClose
case enumspb.TIMEOUT_TYPE_SCHEDULE_TO_START:
return TimerTaskStatusCreatedScheduleToStart
case enumspb.TIMEOUT_TYPE_SCHEDULE_TO_CLOSE:
return TimerTaskStatusCreatedScheduleToClose
case enumspb.TIMEOUT_TYPE_HEARTBEAT:
return TimerTaskStatusCreatedHeartbeat
default:
panic("invalid timeout type")
}
}
// Len implements sort.Interface
func (s TimerSequenceIDs) Len() int {
return len(s)
}
// Swap implements sort.Interface.
func (s TimerSequenceIDs) Swap(
this int,
that int,
) {
s[this], s[that] = s[that], s[this]
}
// Less implements sort.Interface
func (s TimerSequenceIDs) Less(View on GitHub (pinned to bde624efd1)
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.
Example fix
// before (server-side mapping)
case enumspb.TIMEOUT_TYPE_HEARTBEAT:
return TimerTaskStatusCreatedHeartbeat
default:
panic("invalid timeout type")
// after (hardened mapping)
case enumspb.TIMEOUT_TYPE_HEARTBEAT:
return TimerTaskStatusCreatedHeartbeat
case enumspb.TIMEOUT_TYPE_UNSPECIFIED:
ms.logger.Warn("activity with unspecified timeout type", ...)
return TimerTaskStatusCreatedScheduleToClose Defensive patterns
Strategy: validation
Validate before calling
// Application side: always set explicit timeout types when scheduling activities:
activityOptions := workflow.ActivityOptions{
ScheduleToStartTimeout: 10 * time.Second,
StartToCloseTimeout: 30 * time.Second,
// Set every timeout you use explicitly; never leave TimeoutType unset.
} Type guard
func hasValidTimeoutType(t enumspb.TimeoutType) bool {
switch t {
case enumspb.TIMEOUT_TYPE_SCHEDULE_TO_START,
enumspb.TIMEOUT_TYPE_SCHEDULE_TO_CLOSE,
enumspb.TIMEOUT_TYPE_START_TO_CLOSE,
enumspb.TIMEOUT_TYPE_HEARTBEAT:
return true
}
return false // includes TIMEOUT_TYPE_UNSPECIFIED and newer values
} Try / catch
// The panic happens inside the history service, not the SDK caller; recover via // workflow reset rather than catch: // temporal --ns <ns> workflow reset --wid <wid> --eid <event-id> --reason "corrupt activity timeout"
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Current cluster name is empty
- Version increment <= 0 or > 2147483647
- <dynamic updateVersionToClusterName err>
- Current cluster is not specified in cluster info
- Master cluster is not specified in cluster info
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/dd00271a2817ee41.
Report an issue: GitHub.