apache/beam · error

invalid scope

Error message

invalid scope

What it means

TryExternal validates that the provided Scope is valid before constructing an external (cross-language) transform. An invalid or default-constructed Scope (one not bound to a real pipeline/vertex) is rejected with 'invalid scope'.

Source

Thrown at sdks/go/pkg/beam/external.go:40

)

// External defines a Beam external transform. The interpretation of this primitive is runner
// specific. The runner is responsible for parsing the payload based on the
// URN provided to implement the behavior of the operation. Transform
// libraries should expose an API that captures the user's intent and serialize
// the payload as a byte slice that the runner will deserialize.
//
// Use ExternalTagged if the runner will need to associate the PTransforms local PCollection tags
// with values in the payload.
func External(s Scope, urn string, payload []byte, in []PCollection, out []FullType, bounded bool) []PCollection {
	return MustN(TryExternal(s, urn, payload, in, out, bounded))
}

// TryExternal attempts to perform the work of External, returning an error indicating
// why the operation failed.
func TryExternal(s Scope, urn string, payload []byte, in []PCollection, out []FullType, bounded bool) ([]PCollection, error) {
	if !s.IsValid() {
		return nil, errors.New("invalid scope")
	}
	for i, col := range in {
		if !col.IsValid() {
			return nil, errors.Errorf("invalid pcollection to external: index %v", i)
		}
	}

	var ins []*graph.Node
	for _, col := range in {
		ins = append(ins, col.n)
	}
	edge := graph.NewExternal(s.real, s.scope, &graph.Payload{URN: urn, Data: payload}, ins, out, bounded)

	var ret []PCollection
	for _, out := range edge.Output {
		c := PCollection{out.To}
		c.SetCoder(NewCoder(c.Type()))
		ret = append(ret, c)

View on GitHub (pinned to 12126d8942)

Solutions

  1. Derive the scope from the pipeline: use p.Root() or beam.Scope(parent)
  2. Never pass a zero-value Scope{}; always obtain scopes through the beam API
  3. Check col/scope validity early in helper functions with s.IsValid()
  4. If scoping inside composites, create the child scope before the composite body completes

Example fix

// before
var s beam.Scope // zero value, invalid
beam.External(s, urn, payload, in, out, true)
// after
s := beam.Scope(p.Root())
beam.External(s, urn, payload, in, out, true)
Defensive patterns

Strategy: validation

Validate before calling

if !s.IsValid() {
    return errors.New("scope must be derived from p.Root() or beam.Scope(parent), not a zero-value Scope")
}

Type guard

func validScope(s beam.Scope) bool { return s.IsValid() }

Try / catch

cols, err := beam.TryExternal(s, urn, payload, in, out, bounded)
if err != nil {
    if strings.Contains(err.Error(), "invalid scope") { return fmt.Errorf("scope not bound to pipeline: %w", err) }
    return err
}

Prevention

When it happens

Trigger: Calling beam.External/TryExternal with a zero-value Scope, a Scope whose s.IsValid() is false (e.g. Scope{} created directly, or a scope from a finished/closed composite).

Common situations: Creating a Scope with var s beam.Scope instead of deriving it from the pipeline (beam.Scope(p.Root())); passing a scope from another pipeline; using a composite scope after its construction completed.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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