temporalio/temporal · error
unable to encode single payload: %v
Error message
unable to encode single payload: %v
What it means
MustEncodeSingle encodes a single value using the default data converter and panics on failure, by design: the Must-prefix signals callers accept panic-on-error semantics. Encoding fails only when the value is not encodable (unsupported type, nil, or a data converter error), which with the default converter is nearly always a programming mistake.
Source
Thrown at common/payloads/payloads.go:51
func Encode(value ...any) (*commonpb.Payloads, error) {
return defaultDataConverter.ToPayloads(value...)
}
func EncodeSingle(value any) (*commonpb.Payload, error) {
ps, err := defaultDataConverter.ToPayloads(value)
if err != nil {
return nil, err
}
if len(ps.GetPayloads()) < 1 {
return nil, nil
}
return ps.GetPayloads()[0], nil
}
func MustEncodeSingle(value any) *commonpb.Payload {
p, err := EncodeSingle(value)
if err != nil {
panic(fmt.Sprintf("unable to encode single payload: %v", err)) //nolint:forbidigo // Must-helper: callers opt into panic on encode failure
}
return p
}
func MustEncode(value ...any) *commonpb.Payloads {
p, err := defaultDataConverter.ToPayloads(value...)
if err != nil {
panic(fmt.Sprintf("unable to encode payloads: %v", err)) //nolint:forbidigo // Must-helper: callers opt into panic on encode failure
}
return p
}
func Decode(ps *commonpb.Payloads, valuePtr ...any) error {
return defaultDataConverter.FromPayloads(ps, valuePtr...)
}
func ToString(ps *commonpb.Payloads) string {
return fmt.Sprintf("[%s]", strings.Join(defaultDataConverter.ToStrings(ps), ", "))View on GitHub (pinned to bde624efd1)
Solutions
- Check the panicked value's type: ensure it is supported by the configured data converter
- Use EncodeSingle (error-returning) instead of MustEncodeSingle when the value may not be encodable
- Register required payload converters/serializers if using custom types
- In tests, verify the fixture value passed to MustEncodeSingle is not nil
Example fix
// before
payload := payloads.MustEncodeSingle(customType{}) // panics if unsupported
// after
p, err := payloads.EncodeSingle(customType{})
if err != nil {
return fmt.Errorf("encode payload: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
func canEncode(v any) bool { _, err := payloads.EncodeSingle(v); return err == nil } Try / catch
defer func() {
if r := recover(); r != nil {
logger.Error("MustEncodeSingle panicked", r)
err = fmt.Errorf("payload encode failed: %v", r)
}
}() // wrap the call site that uses MustEncodeSingle Prevention
- Prefer EncodeSingle over MustEncodeSingle outside tests
- Verify encoded values are supported by the configured data converter (no nil/channels/functions)
- Register custom converters for application-specific types
- Keep Must* helpers confined to test code and known-safe constant values
When it happens
Trigger: Passing a value that EncodeSingle cannot convert (unsupported type, unmarshalable value, nil where the converter rejects it) to MustEncodeSingle, e.g. in tests like TestHappyPath or workflow code building search-attribute-like payloads.
Common situations: Encoding custom structs without a registered converter; passing nil or channels/functions; swapping the default data converter for one with stricter type support.
Related errors
- unable to encode payloads: %v
- panic(err)
- Current cluster name is empty
- Version increment <= 0 or > 2147483647
- <dynamic updateVersionToClusterName err>
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/420eadef2daa2ac0.
Report an issue: GitHub.