temporalio/temporal · critical

unable to create dynamic config client: %w

Error message

unable to create dynamic config client: %w

What it means

ServerOptionsProvider creates the dynamic config client. When config.DynamicConfigClient is present it calls dynamicconfig.NewFileBasedClientWithMetrics, which loads and validates the dynamic config file; failure (parse error, bad value type, unreadable file) is wrapped as 'unable to create dynamic config client' and blocks startup. With no config block, a noop client is used instead.

Source

Thrown at temporal/fx.go:232

		}
	}

	// EventLoggerProvider backs structured ("wide") events. Select the custom OTEL LoggerProvider
	// if injected, else a no-op provider that discards events. A deployment opts in by injecting a
	// provider via WithCustomEventLoggerProvider.
	eventLoggerProvider := so.eventLoggerProvider
	if eventLoggerProvider == nil {
		eventLoggerProvider = lognoop.NewLoggerProvider()
	}

	// DynamicConfigClient
	dcClient := so.dynamicConfigClient
	if dcClient == nil {
		dcConfig := so.config.DynamicConfigClient
		if dcConfig != nil {
			dcClient, err = dynamicconfig.NewFileBasedClientWithMetrics(dcConfig, logger, stopChan, metricHandler)
			if err != nil {
				return serverOptionsProvider{}, fmt.Errorf("unable to create dynamic config client: %w", err)
			}
		} else {
			// noop client
			logger.Info("Dynamic config client is not configured. Using default values.")
			dcClient = dynamicconfig.NewNoopClient()
		}
	}

	testHooks := testhooks.NewTestHooks()
	if so.testHooks != nil {
		testHooks = *so.testHooks
	}

	// TLSConfigProvider
	tlsConfigProvider := so.tlsConfigProvider
	if tlsConfigProvider == nil {
		tlsConfigProvider, err = encryption.NewTLSConfigProviderFromConfig(so.config.Global.TLS, metricHandler, logger, nil)
		if err != nil {

View on GitHub (pinned to bde624efd1)

Solutions

  1. Fix the wrapped error's cause: correct the file path, YAML syntax, or invalid key/value in the dynamic config file
  2. Validate the file with the temporal server's dynamicconfig tooling (temporal server start-dev or dynamicconfig CLI validation)
  3. If no dynamic overrides are needed, remove the dynamicConfigClient block to use the noop client
  4. Check file permissions/mount correctness in containerized deployments

Example fix

// before
dynamicConfigClient:
  filepath: "config/dynamicconfig/not_exist.yaml"
// after
dynamicConfigClient:
  filepath: "config/dynamicconfig/development.yaml"
Defensive patterns

Strategy: validation

Validate before calling

// validate the dynamic config file before server start
if _, err := os.Stat(dcFilepath); err != nil { log.Fatal(err) }
data, err := os.ReadFile(dcFilepath)
if err != nil { log.Fatal(err) }
var m map[string]any
if err := yaml.Unmarshal(data, &m); err != nil { log.Fatalf("invalid yaml: %v", err) }

Prevention

When it happens

Trigger: dynamicconfig-client block pointing at a YAML file that does not exist, is not valid YAML, or contains a key/value that fails validation (e.g. wrong type for a known key).

Common situations: Wrong filepath in config; file mounted but empty or truncated in Kubernetes; YAML with tabs or type errors; a dynamic config key renamed after a server upgrade with a mismatched value type.

Related errors


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