temporalio/temporal · error · serializer error
%w: cannot serialize %v
Error message
%w: cannot serialize %v
What it means
payloadSerializer.Serialize only accepts *commonpb.Payload (or nil) as the value to serialize into Nexus Content. Any other value type — a raw struct, string, map, etc. — is rejected with this wrapped errSerializer, mirroring the Nexus Go SDK's contract that the Temporal-specific serializer handles Temporal payloads exclusively.
Source
Thrown at common/nexus/payload_serializer.go:107
return nil
}
func setUnknownNexusContent(nexusHeader nexus.Header, payloadMetadata map[string][]byte) {
for k, v := range nexusHeader {
payloadMetadata[k] = []byte(v)
}
payloadMetadata["encoding"] = []byte("unknown/nexus-content")
}
// Serialize implements nexus.Serializer.
func (payloadSerializer) Serialize(v any) (*nexus.Content, error) {
if v == nil {
// Use same structure as the nil serializer from the Nexus Go SDK.
return &nexus.Content{Header: nexus.Header{}}, nil
}
payload, ok := v.(*commonpb.Payload)
if !ok {
return nil, fmt.Errorf("%w: cannot serialize %v", errSerializer, v)
}
// Use the "nil" Nexus Content representation for nil Payloads.
if payload == nil {
// Use same structure as the nil serializer from the Nexus Go SDK.
return &nexus.Content{Header: nexus.Header{}}, nil
}
if len(payload.GetMetadata()) == 0 {
return xTemporalPayload(payload)
}
content := nexus.Content{Header: nexus.Header{}, Data: payload.Data}
encoding := string(payload.Metadata["encoding"])
messageType := string(payload.Metadata["messageType"])
switch encoding {
case "unknown/nexus-content":View on GitHub (pinned to bde624efd1)
Solutions
- Wrap the value in a *commonpb.Payload (Metadata + Data) before serializing.
- Use the default nexus.Serializer if you need to serialize arbitrary Go values.
- Align handler signatures with the configured serializer's supported types.
- Check the %v in the error message to identify the offending type.
Example fix
// before
content, err := serializer.Serialize("hello") // string not supported
// after
content, err := serializer.Serialize(&commonpb.Payload{
Metadata: map[string][]byte{"encoding": []byte("json/plain")},
Data: []byte(`"hello"`),
}) Defensive patterns
Strategy: type-guard
Validate before calling
func canSerializeWithTemporalSerializer(v any) bool {
if v == nil {
return true
}
_, ok := v.(*commonpb.Payload)
return ok
} Type guard
func serializeValue(v any) (*nexus.Content, error) {
if p, ok := v.(*commonpb.Payload); ok || v == nil {
return payloadSerializer{}.Serialize(p)
}
return defaultSerializer{}.Serialize(v) // fall back for arbitrary types
} Try / catch
content, err := serializer.Serialize(v)
if err != nil {
return nil, nexus.HandlerErrorf(nexus.HandlerErrorTypeInternal, "unsupported result type %T", v)
} Prevention
- Return *commonpb.Payload (or nil) from handlers configured with the Temporal serializer
- Keep a compile-time assertion that handler outputs match the serializer contract
- Do not mix serializer configurations between environments
- Cover each handler's result type in a serialization test
When it happens
Trigger: Calling Serialize(v) where v is not *commonpb.Payload — e.g. returning a plain struct or string from a Nexus handler whose server was configured with the Temporal payload serializer.
Common situations: Handler signatures using native Go types while the Temporal serializer is registered; test helpers calling Serialize with arbitrary values; refactors that change handler result types without updating serializer configuration.
Related errors
- %w: cannot deserialize into %v
- serializer error
- cannot serialize HSM task. unable to cast to expected type
- failed to serialize handler result: %w
- %w: payload marshal error: %w
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/681dc9abb64aa41a.
Report an issue: GitHub.