temporalio/temporal · error

could not load config file: %w

Error message

could not load config file: %w

What it means

Returned by serverOptions.loadConfig in temporal/server_options.go:115 when config.Load(WithConfigFile(...)) fails to load an explicit config file path. This wrapper is in turn wrapped by 'unable to load config'. Causes include unreadable file, YAML parse errors, or missing required top-level config sections.

Source

Thrown at temporal/server_options.go:115

	err := so.validateConfig()
	if err != nil {
		return fmt.Errorf("config validation error: %w", err)
	}

	return nil
}

func (so *serverOptions) loadConfig() error {
	if so.configFilePath != "" {
		if so.env != "" || so.configDir != "" || so.zone != "" {
			return errors.New("env, config, zone can not be set if configFilePath is set")
		}
		cfg, err := config.Load(
			config.WithConfigFile(so.configFilePath),
		)
		if err != nil {
			return fmt.Errorf("could not load config file: %w", err)
		}
		so.config = cfg
		return nil
	}
	cfg, err := config.Load(
		config.WithEnv(so.env),
		config.WithConfigDir(so.configDir),
		config.WithZone(so.zone),
	)
	if err != nil {
		return fmt.Errorf("could not load config file: %w", err)
	}
	so.config = cfg
	return nil
}

func (so *serverOptions) validateConfig() error {
	if err := so.config.Validate(); err != nil {

View on GitHub (pinned to bde624efd1)

Solutions

  1. Confirm the file exists and is readable by the process user (ls -l / permissions).
  2. Validate the YAML parses (e.g. yamllint) and matches the temporal server config schema.
  3. Check the innermost wrapped error from config.Load for the precise failure (parse vs missing key).
  4. If you only need to override part of the config, consider configDir+env layout instead of a single explicit file.

Example fix

// before
so := opts; // WithConfigFilePath("config.yaml") relative to a different working dir
// after
temporal.WithConfigFilePath("/absolute/path/to/config.yaml") // always use absolute paths in services
Defensive patterns

Strategy: validation

Validate before calling

path := so.configFilePath
info, err := os.Stat(path)
if err != nil || info.IsDir() {
    return fmt.Errorf("config file %q not readable", path)
}
if err := yaml.Unmarshal([]byte(mustRead(path)), &map[string]any{}); err != nil {
    return fmt.Errorf("config file %q is not valid YAML: %w", path, err)
}

Try / catch

if err := cfgLoaded(); err != nil {
    if errors.Is(err, os.ErrNotExist) {
        log.Fatalf("config file missing: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Using temporal.WithConfigFilePath(path) with the temporal server options where path is nonexistent, unreadable (permissions), not valid YAML, or semantically incomplete per config.Load's requirements.

Common situations: Absolute path typo, Docker/K8s volume not mounted, file copied without the expected schema, YAML indentation errors, or using a config file from an incompatible Temporal version.

Understand the failure class

Background: "Config file not found": what it means and how to fix it in docker-sync, Maven, Vagrant, Turborepo and other tools — this error's family across 60 libraries.

Related errors


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