router-for-me/CLIProxyAPI · critical

failed to parse config file: %w

Error message

failed to parse config file: %w

What it means

The config file was read but gopkg.in/yaml.v3 could not unmarshal it into Config. In optional (cloud deploy) mode a parse failure silently yields an empty config; in normal mode it is fatal here. Typical causes are syntax errors: tabs used for indentation, unquoted special characters, duplicate keys, or truncated files.

Source

Thrown at internal/config/config_load.go:88

	cfg.UsageStatisticsEnabled = false
	cfg.RedisUsageQueueRetentionSeconds = 60
	cfg.DisableCooling = false
	cfg.SaveCooldownStatus = false
	cfg.TransientErrorCooldownSeconds = 0
	cfg.DisableImageGeneration = DisableImageGenerationOff
	cfg.WebsocketAuth = true
	cfg.Pprof.Enable = false
	cfg.Pprof.Addr = DefaultPprofAddr
	cfg.RemoteManagement.PanelGitHubRepository = DefaultPanelGitHubRepository
	cfg.CredentialInFlight = DefaultCredentialInFlightConfig()
	if err = yaml.Unmarshal(data, &cfg); err != nil {
		if optional {
			// In cloud deploy mode, if YAML parsing fails, return empty config instead of error.
			cfgOptional := &Config{CredentialInFlight: DefaultCredentialInFlightConfig()}
			cfgOptional.NormalizePluginsConfig()
			return cfgOptional, nil
		}
		return nil, fmt.Errorf("failed to parse config file: %w", err)
	}

	cfg.CredentialConcurrency = cfg.CredentialConcurrency.WithDefaults()
	if errValidate := cfg.CredentialInFlight.Validate(); errValidate != nil {
		return nil, errValidate
	}
	if errValidate := cfg.Codex.LiveMediaRelay.Validate(); errValidate != nil {
		return nil, errValidate
	}
	if errValidate := cfg.ValidateCredentialWeights(); errValidate != nil {
		return nil, errValidate
	}

	// Hash remote management key if plaintext is detected (nested)
	// We consider a value to be already hashed if it looks like a bcrypt hash ($2a$, $2b$, or $2y$ prefix).
	if cfg.RemoteManagement.SecretKey != "" && !looksLikeBcrypt(cfg.RemoteManagement.SecretKey) {
		hashed, errHash := hashSecret(cfg.RemoteManagement.SecretKey)
		if errHash != nil {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Paste the file into a YAML validator or run 'yamllint config.yaml' — the error offset from yaml.v3 points at the line.
  2. Replace tabs with spaces, quote values containing ': ' or leading special chars.
  3. If the file was truncated by a concurrent writer, restore from source control and write configs atomically (write temp + rename).
  4. Beware optional mode: a silent empty config can mask this error — test parsing explicitly when deploying.

Example fix

# before (tab indentation breaks YAML)
codex:
	live-media-relay:
		enabled: true

# after (spaces)
codex:
  live-media-relay:
    enabled: true
Defensive patterns

Strategy: validation

Validate before calling

// Dry-parse the config before handing it to the server
func configParses(path string) error {
	data, err := os.ReadFile(path)
	if err != nil { return err }
	var probe map[string]any
	return yaml.Unmarshal(data, &probe)
}

Prevention

When it happens

Trigger: yaml.Unmarshal(data, &cfg) returns an error in non-optional mode — e.g. a tab character in indentation, an unquoted ':' inside a value, mismatched quotes, or the file was edited mid-deploy and is half-written.

Common situations: Hand-edited config introducing tabs; secrets with trailing colons or '#' unquoted; CI writing the file non-atomically; mixing JSON and YAML syntax.

Understand the failure class

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/efced1caf432a124. Report an issue: GitHub.