temporalio/temporal · error

serializer error

Error message

serializer error

What it means

errSerializer is the base sentinel error for the nexus payloadSerializer in common/nexus/payload_serializer.go. Serialize and Deserialize wrap it (with fmt.Errorf "%w: ...") when the value being (de)serialized is not the expected *commonpb.Payload type or the underlying persistence serialization fails. Because it is wrapped, callers can match it with errors.Is.

Source

Thrown at common/nexus/payload_serializer.go:17

package nexus

import (
	"errors"
	"fmt"
	"maps"
	"mime"

	"github.com/nexus-rpc/sdk-go/nexus"
	commonpb "go.temporal.io/api/common/v1"
	enumspb "go.temporal.io/api/enums/v1"
	"go.temporal.io/server/common/persistence/serialization"
)

type payloadSerializer struct{}

var errSerializer = errors.New("serializer error")

// Deserialize implements nexus.Serializer.
func (payloadSerializer) Deserialize(content *nexus.Content, v any) error {
	payloadRef, ok := v.(**commonpb.Payload)
	if !ok {
		return fmt.Errorf("%w: cannot deserialize into %v", errSerializer, v)
	}

	payload := &commonpb.Payload{}
	*payloadRef = payload
	payload.Metadata = make(map[string][]byte)
	payload.Data = content.Data

	h := maps.Clone(content.Header)
	// We assume that encoding is handled by the transport layer and the content is decoded.
	delete(h, "encoding")
	// Length can safely be ignored.
	delete(h, "length")

View on GitHub (pinned to bde624efd1)

Solutions

  1. Check errors.Is(err, nexus.ErrSerializer) and read the wrapped detail for the actual cause
  2. Pass **commonpb.Payload (pointer-to-pointer) as the value for Deserialize
  3. For custom types, implement nexus.Serializer instead of relying on the default payload serializer
  4. Inspect the payload data for corruption if the wrapped cause is a persistence serialization failure

Example fix

// before
var s string
cerr := serializer.Deserialize(content, &s)
// after
var payload *commonpb.Payload
if err := serializer.Deserialize(content, &payload); err != nil {
    if errors.Is(err, nexus.ErrSerializer) { /* handle type/serialization mismatch */ }
}
Defensive patterns

Strategy: type-guard

Validate before calling

func asPayload(v any) (*commonpb.Payload, bool) {
    p, ok := v.(*commonpb.Payload)
    return p, ok && p != nil
}

Type guard

payloadRef, ok := v.(**commonpb.Payload)
if !ok { return fmt.Errorf("%w: cannot deserialize into %v", nexus.ErrSerializer, v) }

Try / catch

if err := serializer.Deserialize(content, &payload); err != nil {
    if errors.Is(err, nexus.ErrSerializer) {
        // inspect wrapped cause: wrong target type vs corrupted data
    }
}

Prevention

When it happens

Trigger: Calling Deserialize with a target that is not **commonpb.Payload; calling Serialize with an unsupported value; or an underlying serialization failure while converting between nexus Content and Payload.

Common situations: Passing arbitrary Go values (strings, structs) to the nexus serializer instead of Payload pointers; using a custom serializer with mismatched expectations; corrupted payloads from persistence failing to deserialize.

Related errors


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