apache/beam · error
import failed: options read-only
Error message
import failed: options read-only
What it means
Options.Import seals the options object: it copies RawOptions in and flips the read-only flag so pipeline options can no longer change. Importing twice (or into an already-sealed Options) would allow mutating a pipeline after construction, so it panics.
Source
Thrown at sdks/go/pkg/beam/core/runtime/options.go:87
// harness. The extra layer is currently needed due to Dataflow
// expectations about this representation. Subject to change.
type RawOptionsWrapper struct {
Options RawOptions `json:"beam:option:go_options:v1"`
Runner string `json:"beam:option:runner:v1"`
AppName string `json:"beam:option:app_name:v1"`
Experiments []string `json:"beam:option:experiments:v1"`
RetainDocker bool `json:"beam:option:retain_docker_containers:v1"`
Parallelism int `json:"beam:option:parallelism:v1"`
}
// Import imports the options from previously exported data and makes the
// options read-only. It panics if import is called twice.
func (o *Options) Import(opt RawOptions) {
o.mu.Lock()
defer o.mu.Unlock()
if o.ro {
panic("import failed: options read-only")
}
o.ro = true
o.opt = copyMap(opt.Options)
}
// Get returns the value of the key. If the key has not been set, it returns "".
func (o *Options) Get(key string) string {
o.mu.Lock()
defer o.mu.Unlock()
return o.opt[key]
}
// Set defines the value of the given key. If the key is already defined, it
// panics.
func (o *Options) Set(key, value string) {
o.mu.Lock()
defer o.mu.Unlock()View on GitHub (pinned to 12126d8942)
Solutions
- Call Import exactly once per Options instance, before building the pipeline.
- Create a new Options instance (NewOptions) for each import instead of reusing a sealed one.
- Aggregate all RawOptions into one map and import a single merged RawOptions.
Example fix
// before
opts.Import(raw)
opts.Import(moreRaw) // panics
// after
merged := options.NewRawOptions()
for k, v := range moreRaw.Options { merged.Set(k, v) }
opts.Import(merged) Defensive patterns
Strategy: validation
Validate before calling
if opt.IsReadOnly() { // or track sealing yourself
return errors.New("options already imported; create a new Options")
} Prevention
- Call Import exactly once per Options instance
- Merge all RawOptions before a single Import
- Never share one package-level Options across pipelines or test cases
When it happens
Trigger: Calling opt.Import(raw) a second time on the same *Options, or calling Import on an Options instance that was already sealed by a previous Import (the flag o.ro is true).
Common situations: Tests that import options once in a shared setup helper and again per-case; a library re-importing user options into a shared package-level Options; retry/re-execution logic that re-runs the option-import path.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- trigger.AfterCount(%v) must be a positive integer
- can't apply processing delay of less than a millisecond. Got
- can't apply an alignment period of less than a millisecond.
- GroupIntoBatches: %w
- GroupIntoBatchesWithShardedKey: %w
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/c2119a92c68c9bd4.
Report an issue: GitHub.