apache/beam · error

EnableHook: can't enable hook

Error message

EnableHook: can't enable hook %s, hook %s already enabled

What it means

EnableHook allows only one gRPC hook to be active per process; if a different hook is already enabled it panics with a message naming both hooks. Conflicting hooks would produce incompatible gRPC behavior across the pipeline, so the conflict is treated as fatal.

Solutions

  1. Remove one of the conflicting EnableHook calls so only a single hook is enabled
  2. Use the same hook name everywhere (EnableHook is idempotent for the same name)
  3. Centralize hook enabling in one place (e.g. main) instead of library init() functions
  4. Check hooks.IsEnabled("grpc") and decode the active hook before enabling another

Example fix

// before
grpcx.EnableHook("custom")
grpcx.EnableHook("default") // panics: already enabled
// after
if enabled, opts := hooks.IsEnabled("grpc"); !enabled {
	grpcx.EnableHook("custom")
}
Defensive patterns

Strategy: try-catch

Validate before calling

if enabled, opts := hooks.IsEnabled("grpc"); enabled {
	if n, _ := hooks.Decode(opts[0]); n != desiredName {
		return fmt.Errorf("hook %s already enabled; refusing to enable %s", n, desiredName)
	}
}

Try / catch

defer func() {
	if r := recover(); r != nil {
		err = fmt.Errorf("hook conflict: %v", r)
	}
}()

Prevention

When it happens

Trigger: Calling grpcx.EnableHook("hookA") after grpcx.EnableHook("hookB") has already run (e.g. once from a library's init() and again from pipeline options processing) with different names.

Common situations: Two frameworks/libraries each enabling their own gRPC hook in the same binary; pipeline options being parsed twice with different hook settings; a test harness enabling a hook while the code under test enables another.

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/564294e48389f2e0. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/util/grpcx/hook.go:82

			},
		}
	}
	hooks.RegisterHook("grpc", hf)
}

// EnableHook is called to request the use of the gRPC
// hook in a pipeline.
func EnableHook(name string, opts ...string) {
	_, exists := hookRegistry[name]
	if !exists {
		panic(fmt.Sprintf("EnableHook: %s not registered", name))
	}
	// Only one hook can be enabled. If the pipeline has two conflicting views about how to use gRPC
	// that won't end well.
	if exists, opts := hooks.IsEnabled("grpc"); exists {
		n, _ := hooks.Decode(opts[0])
		if n != name {
			panic(fmt.Sprintf("EnableHook: can't enable hook %s, hook %s already enabled", name, n))
		}
	}

	hooks.EnableHook("grpc", hooks.Encode(name, opts))
}

View on GitHub (pinned to 12126d8942)