{"record":{"id":"0f4929fdde8e9a8a","repo":"temporalio/temporal","slug":"w-payload-marshal-error-w","errorCode":null,"errorMessage":"%w: payload marshal error: %w","messagePattern":"%w: payload marshal error: %w","errorType":"exception","errorClass":"serializer error","httpStatus":null,"severity":"error","filePath":"common/nexus/payload_serializer.go","lineNumber":166,"sourceCode":"\t\t\treturn xTemporalPayload(payload)\n\t\t}\n\t\t// type is unset\n\tcase \"binary/plain\":\n\t\tif len(payload.Metadata) != 1 {\n\t\t\treturn xTemporalPayload(payload)\n\t\t}\n\t\tcontent.Header[\"type\"] = \"application/octet-stream\"\n\tdefault:\n\t\treturn xTemporalPayload(payload)\n\t}\n\n\treturn &content, nil\n}\n\nfunc xTemporalPayload(payload *commonpb.Payload) (*nexus.Content, error) {\n\tdata, err := payload.Marshal()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: payload marshal error: %w\", errSerializer, err)\n\t}\n\treturn &nexus.Content{\n\t\tHeader: nexus.Header{\"type\": \"application/x-temporal-payload\"},\n\t\tData:   data,\n\t}, nil\n}\n\nvar PayloadSerializer nexus.Serializer = payloadSerializer{}\n","sourceCodeStart":148,"sourceCodeEnd":175,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/nexus/payload_serializer.go#L148-L175","documentation":"xTemporalPayload converts a *commonpb.Payload into Nexus Content by calling payload.Marshal() (proto marshal). If the proto message fails to marshal — e.g. it contains data that violates proto3 invariants — the error is wrapped as errSerializer with this message and propagated to Serialize's caller.","triggerScenarios":"Calling Serialize with a *commonpb.Payload whose Marshal() returns an error — typically a payload with unknown/invalid enum values or a corrupt required state produced by manually assembling Metadata/Data.","commonSituations":"Manually constructed Payload structs with invalid fields; payloads deserialized from corrupt persistence or external sources; proto runtime version incompatibilities producing unencodable messages.","solutions":["Log the inner marshal error to identify which field of the Payload is invalid.","Rebuild the Payload through Temporal's data converter APIs instead of hand-assembling it.","Validate the payload (Metadata keys, encoding, Data) before serializing.","Ensure the proto runtime versions match across dependencies (protoimpl conflicts)."],"exampleFix":"// before\npayload := &commonpb.Payload{Metadata: nil, Data: data} // built by hand, fails marshal\n// after\npayload, err := converter.ToPayload(value) // build via data converter\nif err != nil {\n    return err\n}\ncontent, err := serializer.Serialize(payload)","handlingStrategy":"validation","validationCode":"if payload == nil || len(payload.Metadata) == 0 && len(payload.Data) == 0 {\n    return errors.New(\"refusing to serialize empty or hand-built payload\")\n}","typeGuard":"func isMarshalablePayload(p *commonpb.Payload) bool {\n    return p != nil && proto.CheckInitialized(p) == nil\n}","tryCatchPattern":"content, err := serializer.Serialize(payload)\nif err != nil && errors.Is(err, errSerializer) {\n    return nil, fmt.Errorf(\"payload produced by %s is corrupt: %w\", origin, err)\n}","preventionTips":["Build payloads via Temporal data converters instead of hand-assembling structs","Validate payloads read from persistence before re-serializing","Keep protobuf runtime versions consistent across dependencies","Round-trip payloads in tests (ToPayload -> FromPayload) to catch corruption early"],"tags":["nexus","serialization","protobuf","marshal"],"backgroundTag":"protobuf-marshal-error","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}