apache/beam · error

failed to expand cross language transform for edge: %v

Error message

failed to expand cross language transform for edge: %v

What it means

expandCrossLanguage serializes an ExternalTransform edge: it first adds every external input node to the model. If m.addNode fails for any input, the error is wrapped as 'failed to expand cross language transform for edge: %v'. It is a wrapper over a deeper failure (e.g. makeNode/addWindowingStrategy) while expanding a cross-language transform.

Source

Thrown at sdks/go/pkg/beam/core/runtime/graphx/translate.go:745

		Inputs:        inputs,
		Outputs:       outputs,
		EnvironmentId: transformEnvID,
		Annotations:   annotations,
	}
	m.transforms[id] = transform
	allPIds = append(allPIds, id)
	return allPIds, nil
}

func (m *marshaller) expandCrossLanguage(namedEdge NamedEdge) (string, error) {
	edge := namedEdge.Edge
	id := edgeID(edge)

	inputs := make(map[string]string)

	for tag, n := range ExternalInputs(edge) {
		if _, err := m.addNode(n); err != nil {
			return "", errors.Wrapf(err, "failed to expand cross language transform for edge: %v", namedEdge)
		}
		// Ignore tag if it is a dummy UnnamedInputTag
		if tag == graph.UnnamedInputTag {
			tag = fmt.Sprintf("i%v", edge.External.InputsMap[tag])
		}
		inputs[tag] = nodeID(n)
	}

	spec := &pipepb.FunctionSpec{
		Urn:     edge.External.Urn,
		Payload: edge.External.Payload,
	}

	transform := &pipepb.PTransform{
		UniqueName:    namedEdge.Name,
		Spec:          spec,
		Inputs:        inputs,
		EnvironmentId: m.addDefaultEnv(),

View on GitHub (pinned to 12126d8942)

Solutions

  1. Inspect the wrapped inner error to find the true failure (coder or windowing strategy marshal)
  2. Check the input PCollections' coders/windowing are supported by the runner-API marshalling
  3. Ensure all SDKs' container images / expansion service versions are compatible
  4. Report upstream with the full wrapped error chain if the input is a plain default PCollection

Example fix

// before
if _, err := m.addNode(n); err != nil {
    return "", errors.Wrapf(err, "failed to expand cross language transform for edge: %v", namedEdge)
}
// after — log the offending node/tag for diagnosis
if _, err := m.addNode(n); err != nil {
    return "", errors.Wrapf(err, "failed to expand cross language transform for edge %v input tag %q", namedEdge, tag)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify inputs are plain, marshalable PCollections before CrossLanguage
for _, in := range extInputs {
    if in == nil || in.Coder == nil {
        return errors.New("external transform input missing coder")
    }
}

Type guard

func validExternalInput(n *graph.Node) bool { return n != nil && n.Coder != nil && n.WindowingStrategy() != nil }

Try / catch

if err := beam.Run(ctx, pr); err != nil {
    var wrapped *errors.Wrapped
    if errors.As(err, &wrapped) && strings.Contains(err.Error(), "failed to expand cross language transform") {
        log.Printf("cross-language expansion failed: %v", err)
        // fall back to pure-Go transform or fix expansion service
    }
    return err
}

Prevention

When it happens

Trigger: Calling beam.CrossLanguage / an ExternalTransform edge whose input PCollection nodes cannot be marshalled — typically the underlying windowing strategy marshal or coder registration failed inside addNode.

Common situations: Cross-language pipelines (Go driving Python/Java transforms) with exotic windowing or coders on the input side; mismatched SDK versions where the expanded payload references unsupported features.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/1b0a59fa7d647754. Report an issue: GitHub.