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
- Check the wrapped cause to distinguish permission vs path vs I/O problems.
- Fix permissions: chown/chmod the config file for the current user.
- Verify the path points to a regular file, not a directory.
- 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
- Do not run config-writing commands under sudo on a user-owned config.
- Point the config path flag/env at a regular file, not a directory.
- Remember missing files are treated as empty config — only readable-but-failing files need fixing.
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
- MCP server %q not found
- custom provider %q not found
- invalid boolean for llm.use_anthropic: %w
- load config: %w
- load scan template: %w
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/8dd31ad50582ddcb.
Report an issue: GitHub.