apache/beam · error
expansionAddr trying to use unregistered namespace
Error message
expansionAddr %q trying to use unregistered namespace: %q
What it means
The Beam xlangx registry validates expansion addresses before an override is registered. It parses the namespace from the expansion service address and requires a matching handler to have been registered via RegisterNamespaceHandler. If the address's namespace has no handler, this error is thrown to prevent later expansion failures.
Solutions
- Register a handler for the namespace first via xlangx.RegisterNamespaceHandler(ns, handler) before calling RegisterOverrideForUrn.
- Check the parsed namespace with xlangx.ParseAddr (or similar) to confirm what string you must register.
- If the address is a plain expansion URL that should be allowed as-is, verify it passes the URL check; else adjust the address format.
Example fix
// before
xlangx.RegisterOverrideForUrn(urn, "localhost:50051", overrideFn)
// after
xlangx.RegisterNamespaceHandler("localhost:50051", handler)
xlangx.RegisterOverrideForUrn(urn, "localhost:50051", overrideFn) Defensive patterns
Strategy: validation
Validate before calling
ns, _ := xlangx.ParseAddr(expansionAddr) // or registry equivalent
if handler, ok := handlers[ns]; !ok {
return fmt.Errorf("no handler registered for namespace %q", ns)
} Type guard
func hasHandler(ns string) bool { _, ok := xlangx.GetNamespaceHandler(ns); return ok } Try / catch
if err := xlangx.RegisterOverrideForUrn(urn, addr, fn); err != nil {
if strings.Contains(err.Error(), "unregistered namespace") {
xlangx.RegisterNamespaceHandler(ns, handler)
err = xlangx.RegisterOverrideForUrn(urn, addr, fn)
}
} Prevention
- Always pair RegisterNamespaceHandler with RegisterOverrideForUrn in the same setup function.
- Centralize expansion address constants to avoid typos in namespaces.
When it happens
Trigger: Calling RegisterOverrideForUrn with an expansionAddr whose parsed namespace (e.g. the host/URL component or scheme-derived namespace) was never registered with registry.RegisterNamespaceHandler.
Common situations: Typo in the namespace string when registering handlers; using a custom expansion service URL without registering its namespace; switching between local and remote expansion addresses in cross-language pipelines.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- attempted to add namespace to missing coder id
- attempted to add namespace to missing windowing strategy id
- EnableHook: hook not found
- error in startAutomatedPythonExpansionService
- failed to add output coder to coder registry
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/fd22431ad0f62e08.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/xlangx/registry.go:214
r.mu.Lock()
defer r.mu.Unlock()
if err := r.validateAddr(expansionAddr); err != nil {
return fmt.Errorf("xlangx.RegisterExpansionForUrn(%q,%q) error: %v", urn, expansionAddr, err)
}
r.urnOverrides[urn] = expansionAddr
return nil
}
func (r *registry) validateAddr(expansionAddr string) error {
u, err := url.Parse(expansionAddr)
if err == nil && u.Scheme != "" && u.Host != "" {
// This is likely a URL, so allow it.
return nil
}
// Otherwise, let's check that we have a handler registered.
ns, _ := parseAddr(expansionAddr)
if _, ok := r.handlers[ns]; !ok {
return fmt.Errorf("expansionAddr %q trying to use unregistered namespace: %q", expansionAddr, ns)
}
return nil
}
// getHandlerFunc returns HandlerFunc and the config string to put into the params when called.
func (r *registry) getHandlerFunc(urn, expansionAddr string) (HandlerFunc, string) {
r.mu.Lock()
defer r.mu.Unlock()
// By the time this is called, we want *some* kind of HandlerFunc at all,
// So first we check for the hard override.
ns, config := parseAddr(expansionAddr)
if ns == hardOverrideNamespace {
// We have the override namespace and config we must use, so skip the urn step.
expansionAddr = config // The expansionAddr becomes the full config, in case of service.
ns, config = parseAddr(config)
} else if addr, ok := r.urnOverrides[urn]; ok {
// If there is no hard override, check the urn overrides.View on GitHub (pinned to 12126d8942)