alibaba/open-code-review · error

read app config %s: %w

Error message

read app config %s: %w

What it means

LoadAppConfig reads the config file for read-only consumers (e.g. loadLLMRuntime, runLLMTest). If os.ReadFile fails for any reason other than the file not existing (which yields nil, nil), the error is wrapped as 'read app config <path>: %w'. Unlike loadOrCreateConfig, a missing file is not an error.

Source

Thrown at cmd/opencodereview/config_cmd.go:408

			return &Config{}, nil
		}
		return nil, err
	}
	var cfg Config
	if err := json.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("parse config: %w", err)
	}
	return &cfg, nil
}

// LoadAppConfig loads config from path. Returns nil, nil if file does not exist.
func LoadAppConfig(path string) (*Config, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, fmt.Errorf("read app config %s: %w", path, err)
	}
	var cfg Config
	if err := json.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("parse app config: %w", err)
	}
	return &cfg, nil
}

// supportedConfigKeys is the single source of truth for the top-level config
// keys accepted by setConfigValue. The unknown-key error message is generated
// from this list so the two cannot drift apart when a new key is added.
var supportedConfigKeys = []string{
	"provider",
	"model",
	"max_tokens",
	"effort",
	"providers.<name>.<field>",
	"custom_providers.<name>.<field>",

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Check the wrapped cause to distinguish permission vs path vs I/O problems.
  2. Fix permissions: chown/chmod the config file for the current user.
  3. Verify the path points to a regular file, not a directory.
  4. If the config is optional, remember a missing file is fine (returns nil, nil) — only fix genuine read failures.

Example fix

// before
$ sudo ocr config set provider x  # config now root-owned
$ ocr llm test
read app config /home/u/.ocr/config.json: permission denied

// after
$ sudo chown -R $USER ~/.ocr && ocr llm test
Defensive patterns

Strategy: try-catch

Validate before calling

info, err := os.Stat(path)
if err == nil && info.IsDir() {
    return fmt.Errorf("%s is a directory, expected a config file", path)
}
if err == nil && info.Mode().Perm()&0o400 == 0 {
    return fmt.Errorf("%s is not readable by current user", path)
}

Try / catch

cfg, err := LoadAppConfig(path)
if err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) && errors.Is(perr.Err, fs.ErrPermission) {
        fmt.Fprintf(os.Stderr, "fix permissions on %s\n", path)
    }
    return err
}

Prevention

When it happens

Trigger: Calling LoadAppConfig (directly or via LLM runtime setup / 'ocr llm test') when the config path exists but cannot be read: permission denied, path is a directory, I/O error, or symlink to an unreadable target.

Common situations: Config file created with sudo and 0600 root ownership; OCR config path env/flag pointing at a directory; NFS/disk errors; file deleted between existence check and read in a race.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/8dd31ad50582ddcb. Report an issue: GitHub.