zitadel/zitadel · error

unable to set logger: %w

Error message

unable to set logger: %w

What it means

cmd/ready's newConfig wraps any failure from config.Log.SetLogger() with "unable to set logger: %w". The ready command needs a working logger before it runs health probes; if the legacy logger cannot be constructed from the config (logging config invalid, sink not writable, formatter misconfigured), startup aborts with this wrapper. The underlying cause is always in the wrapped error.

Source

Thrown at cmd/ready/config.go:47

		viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
			hook.Base64ToBytesHookFunc(),
			mapstructure.StringToTimeDurationHookFunc(),
			mapstructure.StringToTimeHookFunc(time.RFC3339),
			mapstructure.StringToSliceHookFunc(","),
			hook.EnumHookFunc(internal_authz.MemberTypeString),
			mapstructure.TextUnmarshallerHookFunc(),
		)),
	)
	if err != nil {
		return nil, nil, fmt.Errorf("unable to read default config: %w", err)
	}
	// Force-disable metrics and tracing for ready command
	config.Instrumentation.Metric.Exporter.Type = instrumentation.ExporterTypeNone
	config.Instrumentation.Trace.Exporter.Type = instrumentation.ExporterTypeNone
	// Legacy logger
	err = config.Log.SetLogger()
	if err != nil {
		return nil, nil, fmt.Errorf("unable to set logger: %w", err)
	}

	shutdown, err := instrumentation.Start(cmd.Context(), config.Instrumentation)
	if err != nil {
		return nil, nil, fmt.Errorf("unable to start instrumentation: %w", err)
	}
	cmd.SetContext(logging.NewCtx(cmd.Context(), logging.StreamRuntime))

	return config, shutdown, nil
}

View on GitHub (pinned to 13948f2bcd)

Solutions

  1. Read the wrapped %w cause in the error output; fix the specific logger config problem it names.
  2. Validate the Log section in config.yaml / ZITADEL_LOG* env vars (valid level, formatter, sink).
  3. Run with default logging (remove custom Log overrides) to confirm the custom config is the culprit.

Example fix

// before (config.yaml)
Log:
  Level: verbosedebug
// after
Log:
  Level: debug
Defensive patterns

Strategy: validation

Validate before calling

cfg, _ := readConfig()
if cfg.Log.Level == "" || !isValidLogLevel(cfg.Log.Level) {
    return fmt.Errorf("invalid log level %q", cfg.Log.Level)
}

Try / catch

if err := config.Log.SetLogger(); err != nil {
    return fmt.Errorf("unable to set logger: %w", err)
}

Prevention

When it happens

Trigger: Running `zitadel ready` with a Log config section that SetLogger() rejects — e.g. an invalid log level, unsupported formatter in LogSlog/legacy config, or a log destination that cannot be opened.

Common situations: Misquoted or invalid YAML in the Log section of config.yaml; ZITADEL_LOG_* env vars set to invalid values; running ready in a container where the configured log file path is not writable.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of zitadel/zitadel@13948f2bcd (2026-09-06). Data as JSON: /api/errors/80b58d3cc53b4032. Report an issue: GitHub.