temporalio/temporal · critical
unsupported error type: %v
Error message
unsupported error type: %v
What it means
configuredFaultInjector builds fault objects from dynamic-config fault-injection rules, mapping an error type name (e.g. "ResourceExhausted", "Unavailable") to a concrete serviceerror constructor. An error name outside the supported set panics, because fault injection config is validated only at use time. This is a configuration-driven panic, so bad dynamic config can crash the calling service.
Source
Thrown at common/persistence/faultinjection/fault.go:57
return newFaultFromError(fmt.Errorf("%s: %w", header, context.DeadlineExceeded), errRate)
case "Timeout":
return newFaultFromError(&persistence.TimeoutError{Msg: fmt.Sprintf("%s: persistence.TimeoutError", header)}, errRate)
case "ExecuteAndTimeout":
// Special error which emulates case, when caller got a Timeout error,
// but operation actually reached persistence and was executed successfully.
f := newFaultFromError(&persistence.TimeoutError{Msg: fmt.Sprintf("%s: persistence.TimeoutError", header)}, errRate)
f.execOp = true
return f
case "ResourceExhausted":
return newFaultFromError(&serviceerror.ResourceExhausted{
Cause: enumspb.RESOURCE_EXHAUSTED_CAUSE_SYSTEM_OVERLOADED,
Scope: enumspb.RESOURCE_EXHAUSTED_SCOPE_SYSTEM,
Message: fmt.Sprintf("%s: serviceerror.ResourceExhausted", header),
}, errRate)
case "Unavailable":
return newFaultFromError(serviceerror.NewUnavailablef("%s: serviceerror.Unavailable", header), errRate)
default:
panic(fmt.Sprintf("unsupported error type: %v", errName))
}
}
func (f *fault) inject(op func() error) error {
if f == nil {
return op()
}
if f.execOp {
err := op()
if err != nil {
return err
}
}
return f.err
}
View on GitHub (pinned to bde624efd1)
Solutions
- Check the fault-injection dynamic config entry and correct the error name to a supported value (e.g. "ResourceExhausted", "Unavailable")
- Match the exact casing used in the switch statement in common/persistence/faultinjection/fault.go
- Validate fault-injection config in a staging environment before applying to production
- If you need another error type, add a case to newFault's switch and deploy the change
Example fix
// before (dynamic config YAML) faultInjection: error: ResourceExhaustion # typo -> panic // after faultInjection: error: ResourceExhausted # supported name
Defensive patterns
Strategy: validation
Validate before calling
supported := map[string]bool{"ResourceExhausted": true, "Unavailable": true}
if !supported[errName] {
return fmt.Errorf("unsupported fault injection error type: %q", errName)
} Prevention
- Validate fault-injection dynamic config values before applying them
- Use exact supported names/casing from the fault.go switch
- Test fault-injection config in staging before production
- Never enable fault injection in production clusters
When it happens
Trigger: Setting the fault-injection dynamic config with an error name not in the supported map (typos like "ResourceExhaustion", unsupported types like "InvalidArgument" if unimplemented, or wrong casing) — newFault is then called with that errName.
Common situations: Typos or wrong casing in fault-injection dynamic config values; copying config examples from newer versions supporting more error types; enabling fault injection in production config by mistake.
Related errors
- Can't deep copy non-zero time.Time: %v
- Can't deep copy value of type %s: %v
- ConvertGradualChange can only be used with scalar types for
- dynamicconfig.New*Setting must only be called from static in
- duplicate registration of dynamic config key: %q
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/c9f0aebdcde771b3.
Report an issue: GitHub.