temporalio/temporal · error

duplicate registration of dynamic config key

Error message

duplicate registration of dynamic config key: %q

What it means

register() enforces that each dynamic config Key is registered at most once; a second New*Setting call with the same key string panics. Duplicate keys would make queryRegistry ambiguous, so the failure is made loud at startup.

Solutions

  1. Rename one of the duplicate keys so each is unique (follow the component-prefix convention, e.g. matching., history.)
  2. Delete the redundant declaration if the setting already exists elsewhere
  3. Search the codebase for the key string before adding a new setting

Example fix

// before (two files)
var a = NewBoolSetting("matching.flag", false, ...)
var b = NewBoolSetting("matching.flag", true, ...)
// after
var a = NewBoolSetting("matching.flag", false, ...)
var b = NewBoolSetting("matching.otherFlag", true, ...)
Defensive patterns

Strategy: validation

Validate before calling

// grep for key before adding

Prevention

When it happens

Trigger: Two packages (or two vars in one package) declaring settings with the identical key string, e.g. two copies of NewBoolSetting("history.xxx", ...) after a copy-paste or a package split; tests declaring the same key in multiple files.

Common situations: Copy-pasting a setting declaration to a new file without renaming the key; merging branches that each added a setting with the same name; re-running declarations in test binaries sharing globals.

Related errors


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

Appendix: source

Thrown at common/dynamicconfig/registry.go:28

		settings map[Key]GenericSetting
		queried  atomic.Bool
	}
)

var (
	globalRegistry registry
)

func register(s GenericSetting) {
	if globalRegistry.queried.Load() {
		panic("dynamicconfig.New*Setting must only be called from static initializers")
	}
	if globalRegistry.settings == nil {
		globalRegistry.settings = make(map[Key]GenericSetting)
	}
	if globalRegistry.settings[s.Key()] != nil {
		// nolint:forbidigo // only called during static initialization
		panic(fmt.Sprintf("duplicate registration of dynamic config key: %q", s.Key().String()))
	}
	globalRegistry.settings[s.Key()] = s
}

func queryRegistry(k Key) GenericSetting {
	if !globalRegistry.queried.Load() {
		globalRegistry.queried.Store(true)
	}
	return globalRegistry.settings[k]
}

// For testing only; do not call from regular code!
func ResetRegistryForTest() {
	globalRegistry.settings = nil
	globalRegistry.queried.Store(false)
}

View on GitHub (pinned to bde624efd1)