apache/beam · error

Init hooks have already run. Register hook during init()…

Error message

Init hooks have already run. Register hook during init() instead.

What it means

runtime.RegisterInit queues hooks that run once when beam.Init() executes; after Init has run, the hooks slice is frozen (initialized=true). Registering later would silently never run, so the library panics to force registration in init() time.

Solutions

  1. Move the RegisterInit call into a package init() function so it runs before beam.Init().
  2. If you cannot use init(), ensure RegisterInit executes before any call to beam.Init() in main.
  3. Restructure so the hook's work happens after Init via a different mechanism (e.g. call the function directly after Init).

Example fix

// before
func main() {
    beam.Init()
    runtime.RegisterInit(myHook) // panics
}
// after
func init() {
    runtime.RegisterInit(myHook)
}
func main() {
    beam.Init()
}
Defensive patterns

Strategy: validation

Validate before calling

// call only from package init(), before beam.Init()
func init() { runtime.RegisterInit(myHook) }

Prevention

When it happens

Trigger: Calling runtime.RegisterInit(func(){...}) from normal program flow (a test's Setup, a handler, main after beam.Init()) rather than from a package init() function.

Common situations: Moving beam.Init() earlier in main so it precedes registration; a lazily-imported package whose registration code runs post-Init; tests that call beam.Init() in TestMain and then register hooks in individual tests.

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


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

Appendix: source

Thrown at sdks/go/pkg/beam/core/runtime/init.go:31

// See the License for the specific language governing permissions and
// limitations under the License.

// Package runtime contains runtime hooks and utilities for pipeline options
// and type registration. Most functionality done in init and hence is
// available both during pipeline-submission and at runtime.
package runtime

var (
	hooks       []func()
	initialized bool
)

// RegisterInit registers an Init hook. Hooks are expected to be able to
// figure out whether they apply on their own, notably if invoked in a remote
// execution environment. They are all executed regardless of the runner.
func RegisterInit(hook func()) {
	if initialized {
		panic("Init hooks have already run. Register hook during init() instead.")
	}

	hooks = append(hooks, hook)
}

// Init is the hook that all user code must call after flags processing and
// other static initialization, for now.
func Init() {
	initialized = true
	for _, hook := range hooks {
		hook()
	}
}

// Initialized exposes the initialization status for runners.
func Initialized() bool {
	return initialized
}

View on GitHub (pinned to 12126d8942)