temporalio/temporal · error

nexus service is already registered

Error message

nexus service %s is already registered

What it means

registerNexusService rejects registering a nexus.Service whose Name already exists in r.nexusServices. Nexus service names must be unique in the registry because they route inbound Nexus calls to handlers.

Solutions

  1. Remove the duplicate registration so each nexus service name is registered once.
  2. Give the second service a unique name.
  3. If both packages need the same service, export one registration and import it instead of duplicating.

Example fix

// before
reg.RegisterNexusService(nexus.NewService("billing", ...))
reg.RegisterNexusService(nexus.NewService("billing", ...))
// after
reg.RegisterNexusService(nexus.NewService("billing", ...))
Defensive patterns

Strategy: validation

Validate before calling

if registeredNexusNames[svc.Name] {
	return fmt.Errorf("nexus service %s already registered", svc.Name)
}

Try / catch

if err := registerNexusService(reg, svc); err != nil && strings.Contains(err.Error(), "is already registered") {
	return nil // idempotent bootstrap
}

Prevention

When it happens

Trigger: Registering the same nexus service name twice via chasm.Register; two packages' init() both registering a service with the same name; registering two distinct nexus.Service instances that share a name.

Common situations: Shared infrastructure package and app bootstrap both registering the same service name; renaming a service but leaving the old registration in place; multi-tenant setups reusing a name across libraries loaded into one binary.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/57baceb17bc4a7f5. Report an issue: GitHub.

Appendix: source

Thrown at chasm/registry.go:370

	return nil
}

func (r *Registry) warnUnmanagedFields(fqn string, rc *RegistrableComponent) {
	var unmanagedFields []string
	for f := range unmanagedFieldsOf(rc.goType) {
		unmanagedFields = append(unmanagedFields, fmt.Sprintf("%s %s", f.name, f.typ))
	}
	if len(unmanagedFields) > 0 {
		r.logger.Info(fmt.Sprintf(
			"Warning: CHASM component %s declares state fields that won't be managed by CHASM:\n\t%s",
			fqn,
			strings.Join(unmanagedFields, "\n\t")))
	}
}

func (r *Registry) registerNexusService(svc *nexus.Service) error {
	if _, ok := r.nexusServices[svc.Name]; ok {
		return fmt.Errorf("nexus service %s is already registered", svc.Name)
	}
	r.nexusServices[svc.Name] = svc
	return nil
}

// NexusServices returns all registered Nexus services.
func (r *Registry) NexusServices() map[string]*nexus.Service {
	// Return a copy to prevent external modification
	services := make(map[string]*nexus.Service, len(r.nexusServices))
	maps.Copy(services, r.nexusServices)
	return services
}

func (r *Registry) componentContextValue(key any) any {
	if v, ok := r.rcContextValues[key]; ok {
		return v.v
	}
	return nil

View on GitHub (pinned to bde624efd1)