jaegertracing/jaeger · error

invalid configuration

Error message

invalid configuration: %w

What it means

After a successful Viper unmarshal, LoadConfigFromViper calls Config.Validate() and wraps any validation failure as `invalid configuration: %w`. This means the config parsed but is semantically rejected — either by storageconfig.Config.Validate() (backend-specific constraints) or because more than one trace backend was configured for the remote-storage service.

Solutions

  1. Read the wrapped inner error to see which validation rule failed
  2. Ensure at most one backend is defined under storage.trace_backends (remote-storage is single-backend)
  3. Ensure the single backend entry includes its required type-specific block (e.g. `memory:` or `cassandra:`)
  4. Run with the DefaultConfig-style structure as a reference and adjust field-by-field

Example fix

// before
storage:
  trace_backends:
    memory: {memory: {max_traces: 1000000}}
    cassandra: {cassandra: {servers: [cassandra:9042]}}
// after
storage:
  trace_backends:
    cassandra: {cassandra: {servers: [cassandra:9042]}}
Defensive patterns

Strategy: validation

Validate before calling

backends := v.GetStringMap("storage.trace_backends")
if len(backends) > 1 {
    return fmt.Errorf("remote-storage supports one backend, got %d", len(backends))
}
if len(backends) == 1 {
    for name, cfgAny := range backends {
        m, ok := cfgAny.(map[string]any)
        if !ok || len(m) == 0 {
            return fmt.Errorf("backend %q has empty configuration", name)
        }
    }
}

Try / catch

cfg, err := app.LoadConfigFromViper(v)
if err != nil {
    if strings.Contains(err.Error(), "invalid configuration") {
        // semantic validation failed; inspect wrapped cause for the rule
        fmt.Fprintf(os.Stderr, "config rejected: %v\n", err)
        os.Exit(1)
    }
    return err
}

Prevention

When it happens

Trigger: Calling LoadConfigFromViper with structurally valid YAML that fails cfg.Validate(): e.g. two entries under storage.trace_backends, or a backend entry violating the storage config's own validation rules (missing required fields for the declared backend type).

Common situations: Copying the main `jaeger` binary's multi-backend storage config into remote-storage; defining both a memory and a cassandra backend; leaving a backend entry empty/missing its type-specific configuration block.

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 jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/8d68e1d721219b1c. Report an issue: GitHub.

Appendix: source

Thrown at cmd/remote-storage/app/config.go:38

	GRPC    configgrpc.ServerConfig `mapstructure:"grpc"`
	Tenancy tenancy.Options         `mapstructure:"multi_tenancy"`
	// This configuration is the same as of the main `jaeger` binary,
	// but only one backend should be defined.
	Storage storageconfig.Config `mapstructure:"storage"`
}

// LoadConfigFromViper loads the configuration from Viper.
func LoadConfigFromViper(v *viper.Viper) (*Config, error) {
	cfg := &Config{}

	// Unmarshal the entire configuration
	if err := v.Unmarshal(cfg); err != nil {
		return nil, fmt.Errorf("failed to unmarshal configuration: %w", err)
	}

	// Validate storage configuration
	if err := cfg.Validate(); err != nil {
		return nil, fmt.Errorf("invalid configuration: %w", err)
	}

	return cfg, nil
}

// Validate validates the configuration.
func (c *Config) Validate() error {
	// Validate storage configuration
	if err := c.Storage.Validate(); err != nil {
		return err
	}

	// Ensure only one backend is defined for remote-storage
	if len(c.Storage.TraceBackends) > 1 {
		return fmt.Errorf("remote-storage only supports a single storage backend, but %d were configured", len(c.Storage.TraceBackends))
	}

	return nil

View on GitHub (pinned to 806f444784)