temporalio/temporal · error

failed to deserialize data: %w

Error message

failed to deserialize data: %w

What it means

prepareDataValue in chasm/tree.go lazily deserializes a data node's stored payload into valueT when valueState is valueStateNeedDeserialize. On failure the error is wrapped with 'failed to deserialize data'. This means the node's DataAttributes payload cannot be decoded into the expected Go value type.

Source

Thrown at chasm/tree.go:648

	return nil
}

func (n *Node) prepareDataValue(
	chasmContext Context,
	valueT reflect.Type,
) error {
	metadata := n.serializedNode.Metadata
	dataAttr := metadata.GetDataAttributes()
	if dataAttr == nil {
		return softassert.UnexpectedInternalErr(
			n.logger,
			"expect chasm node to have DataAttributes",
			fmt.Errorf("actual attributes: %v", metadata.Attributes))
	}

	if n.valueState == valueStateNeedDeserialize {
		if err := n.deserialize(valueT); err != nil {
			return fmt.Errorf("failed to deserialize data: %w", err)
		}
	}

	// For now, we assume if a node is accessed with a MutableContext,
	// its value will be mutated and no longer in sync with the serializedNode.
	_, componentCanBeMutated := chasmContext.(MutableContext)
	if componentCanBeMutated {
		n.setValueState(valueStateNeedSerialize)
	}

	return nil
}

func (n *Node) preparePointerValue() error {
	metadata := n.serializedNode.Metadata
	pointerAttr := metadata.GetPointerAttributes()
	if pointerAttr == nil {
		return softassert.UnexpectedInternalErr(

View on GitHub (pinned to bde624efd1)

Solutions

  1. Confirm the type used to read the data node matches the type used when it was written
  2. Check for schema/type changes since the data was persisted and add backward compatibility
  3. Inspect the stored payload for the failing node to verify it is intact and non-empty
  4. Re-write or delete the offending node data if it is confirmed corrupt

Example fix

// before
var out map[string]int
chasmCtx.GetValue(node) // node was written as map[string]string
// after
var out map[string]string
val := chasmCtx.GetValue(node)
converted := map[string]int{}
for k, v := range val { converted[k] = len(v) }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the read type matches the write type before calling accessors:
var expect map[string]string
_ = expect // use the same generic type the node was written with

Type guard

func dataMatches[T any](want T, meta NodeMetadata) bool { /* compare metadata's registered value type against reflect.TypeOf(want) */ return reflect.TypeOf(want).String() == meta.ValueTypeName }

Try / catch

v := chasmCtx.GetData(myNode)
// deserialization errors surface here; wrap access in a helper:
func safeGet[T any](c chasm.Context, n Node) (T, error) {
  var out T
  if err := c.GetValueInto(n, &out); err != nil {
    return out, fmt.Errorf("read data node: %w", err)
  }
  return out, nil
}

Prevention

When it happens

Trigger: Reading a CHASM data node value (via a Context accessor) after the node was loaded from persistence in need-of-deserialize state and n.deserialize(valueT) fails — typically because the persisted bytes do not match the requested type or are corrupt.

Common situations: Requesting a data value with the wrong generic type parameter (schema drift between writer and reader), changing a data field's type without migration, or corrupted node payloads after failed writes.

Related errors


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