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

  1. Check the panicked value's type: ensure it is supported by the configured data converter
  2. Use EncodeSingle (error-returning) instead of MustEncodeSingle when the value may not be encodable
  3. Register required payload converters/serializers if using custom types
  4. 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

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


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/420eadef2daa2ac0. Report an issue: GitHub.