apache/beam · critical

outputTypes already set as: %v

Error message

outputTypes already set as: 
%v

What it means

ExternalTransform.WithNamedOutputs sets the tag→output-index map for cross-language transforms. Like WithNamedInputs it may only be called once; a second call when OutputsMap is already set panics with 'outputTypes already set as: ...'.

Source

Thrown at sdks/go/pkg/beam/core/graph/xlang.go:90

	Expanded *ExpandedTransform
}

// WithNamedInputs adds a map (tag -> index of Inbound in MultiEdge.Input)
// of named inputs corresponsing to ExternalTransform's InputsMap
func (ext ExternalTransform) WithNamedInputs(inputsMap map[string]int) ExternalTransform {
	if ext.InputsMap != nil {
		panic(errors.Errorf("inputs already set as: \n%v", ext.InputsMap))
	}
	ext.InputsMap = inputsMap
	return ext
}

// WithNamedOutputs adds a map (tag -> index of Outbound in MultiEdge.Output)
// of named outputs corresponsing to ExternalTransform's OutputsMap
func (ext ExternalTransform) WithNamedOutputs(outputsMap map[string]int) ExternalTransform {
	if ext.OutputsMap != nil {
		panic(errors.Errorf("outputTypes already set as: \n%v", ext.OutputsMap))
	}
	ext.OutputsMap = outputsMap
	return ext
}

// NewNamespaceGenerator returns a functions that generates a random string of n alphabets
func NewNamespaceGenerator(n int) func() string {
	const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	const (
		letterIDBits = 6                   // 6 bits to represent a letter index
		letterIDMask = 1<<letterIDBits - 1 // All 1-bits, as many as letterIDBits
		letterIDMax  = 63 / letterIDBits   // # of letter indices fitting in 63 bits
	)

	var src = rand.NewSource(time.Now().UnixNano())

	random := func() string {
		sb := strings.Builder{}

View on GitHub (pinned to 12126d8942)

Solutions

  1. Call WithNamedOutputs exactly once per ExternalTransform; remove the redundant call.
  2. Construct a new ExternalTransform if a different output map must be applied.
  3. Condition the call on `ext.OutputsMap == nil` in builder helpers.
  4. Use the panic's printed existing map to identify and reconcile the conflicting call site.

Example fix

// before
ext = ext.WithNamedOutputs(outs)
ext = ext.WithNamedOutputs(outs2) // panics
// after
ext = ext.WithNamedOutputs(outs)
Defensive patterns

Strategy: validation

Validate before calling

if ext.OutputsMap == nil {
    ext = ext.WithNamedOutputs(outputsMap)
}

Try / catch

func safeWithOutputs(ext graph.ExternalTransform, m map[string]int) (r graph.ExternalTransform) {
    defer func() { if rec := recover(); rec != nil { log.Printf("outputs already set: %v", rec) } }()
    return ext.WithNamedOutputs(m)
}

Prevention

When it happens

Trigger: Calling WithNamedOutputs twice on the same ExternalTransform (duplicate builder invocation), before the transform is expanded into the graph.

Common situations: Chaining builder calls in two places (helper + caller); re-running construction logic on a retained ExternalTransform; copy-paste duplication when wiring multi-output external transforms.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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