apache/beam · error

RegisterTraceCaptureHook

Error message

RegisterTraceCaptureHook: %s registered twice

What it means

RegisterTraceCaptureHook stores a trace CaptureHookFactory in traceCaptureHookRegistry and panics if the same identifier is already registered. Like the profile hook registry, it is designed to fail fast at init time when two code paths claim the same hook name.

Solutions

  1. Locate all call sites registering that trace hook name and keep exactly one.
  2. Move registration to a single package init and rely on blank imports elsewhere.
  3. Deduplicate the dependency tree if two versions of the hook package are both linked.
  4. Wrap dynamic registrations in sync.Once or check registration state before calling.

Example fix

// before
perf.RegisterTraceCaptureHook("mytrace", f)
perf.RegisterTraceCaptureHook("mytrace", g) // panics
// after
perf.RegisterTraceCaptureHook("mytrace", f) // single registration only
Defensive patterns

Strategy: validation

Validate before calling

if _, exists := traceRegistered["mytrace"]; !exists {
    perf.RegisterTraceCaptureHook("mytrace", myFactory)
}

Try / catch

func registerTrace(name string, f perf.CaptureHookFactory) {
    defer func() {
        if r := recover(); r != nil {
            log.Printf("trace hook %q duplicate registration ignored: %v", name, r)
        }
    }()
    perf.RegisterTraceCaptureHook(name, f)
}

Prevention

When it happens

Trigger: Calling perf.RegisterTraceCaptureHook(name, factory) with a name already in traceCaptureHookRegistry — duplicate init() registrations, a test helper registering a hook that production init also registers, or two copies of the hook package linked via different module versions.

Common situations: Multiple instrumentation packages registering identically-named trace hooks; re-registering during test re-runs within the same process; vendored forks of a hook package both executing init.

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/x/hooks/perf/perf.go:177

			enabledProfCaptureHooks[i] = enc
			hooks.EnableHook("prof", enabledProfCaptureHooks...)
			return
		}
	}

	enabledProfCaptureHooks = append(enabledProfCaptureHooks, enc)
	hooks.EnableHook("prof", enabledProfCaptureHooks...)
}

var traceCaptureHookRegistry = make(map[string]CaptureHookFactory)
var enabledTraceCaptureHooks []string

// RegisterTraceCaptureHook registers a CaptureHookFactory for the
// supplied identifier. It panics if the same identifier is
// registered twice.
func RegisterTraceCaptureHook(name string, c CaptureHookFactory) {
	if _, exists := traceCaptureHookRegistry[name]; exists {
		panic(fmt.Sprintf("RegisterTraceCaptureHook: %s registered twice", name))
	}
	traceCaptureHookRegistry[name] = c
}

// EnableTraceCaptureHook actives a registered profile capture hook for a given pipeline.
func EnableTraceCaptureHook(name string, opts ...string) {
	if _, exists := traceCaptureHookRegistry[name]; !exists {
		panic(fmt.Sprintf("EnableTraceCaptureHook: %s not registered", name))
	}

	enc := hooks.Encode(name, opts)
	for i, h := range enabledTraceCaptureHooks {
		n, _ := hooks.Decode(h)
		if h == n {
			// Rewrite the registration with the current arguments
			enabledTraceCaptureHooks[i] = enc
			hooks.EnableHook("trace", enabledTraceCaptureHooks...)
			return

View on GitHub (pinned to 12126d8942)