multica-ai/multica · error
read CLI config: %w
Error message
read CLI config: %w
What it means
LoadCLIConfigForProfile failed to read the profile's config.json from disk with an error other than 'file does not exist' (that case returns a zero config successfully). The underlying os.ReadFile error is wrapped, so the message ends with EACCES, EISDIR, or a similar errno. It only fires when the path resolved fine but the read itself was denied.
Source
Thrown at server/internal/cli/config.go:302
}
// LoadCLIConfig reads the CLI config from disk (default profile).
func LoadCLIConfig() (CLIConfig, error) {
return LoadCLIConfigForProfile("")
}
// LoadCLIConfigForProfile reads the CLI config for the given profile.
func LoadCLIConfigForProfile(profile string) (CLIConfig, error) {
path, err := CLIConfigPathForProfile(profile)
if err != nil {
return CLIConfig{}, err
}
data, err := os.ReadFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return CLIConfig{}, nil
}
return CLIConfig{}, fmt.Errorf("read CLI config: %w", err)
}
var cfg CLIConfig
if err := json.Unmarshal(data, &cfg); err != nil {
return CLIConfig{}, fmt.Errorf("parse CLI config: %w", err)
}
return cfg, nil
}
// SaveCLIConfig writes the CLI config to disk atomically (default profile).
func SaveCLIConfig(cfg CLIConfig) error {
return SaveCLIConfigForProfile(cfg, "")
}
// SaveCLIConfigForProfile writes the CLI config for the given profile.
func SaveCLIConfigForProfile(cfg CLIConfig, profile string) error {
path, err := CLIConfigPathForProfile(profile)
if err != nil {
return errView on GitHub (pinned to 2c0912b6ec)
Solutions
- Check ownership of the file shown in the wrapped error and chown it back to the current user (e.g. sudo chown -R $(whoami) ~/.multica)
- Verify permissions with ls -l on the path; chmod 600 the file if needed
- If MULTICA_TASK_CONFIG_ROOT is set, confirm it points at a directory this user owns and unset it if the daemon context is unintended
- If the file is not meant to exist, delete it so the next load takes the clean 'missing file' path instead
Example fix
# before $ multica config get read CLI config: open /home/user/.multica/config.json: permission denied # after $ sudo chown -R $(whoami) ~/.multica $ multica config get
Defensive patterns
Strategy: try-catch
Validate before calling
if path, err := cli.CLIConfigPathForProfile(profile); err == nil {
if info, statErr := os.Stat(path); statErr == nil && info.Mode().Perm()&0o400 != 0o400 {
// file exists but may not be readable by this user
}
} Type guard
func isReadableConfigErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "read CLI config:")
} Try / catch
cfg, err := cli.LoadCLIConfigForProfile(profile)
if err != nil {
if errors.Is(err, os.ErrPermission) {
// surface an actionable message about ownership/permissions
}
return err
} Prevention
- Never run the CLI under sudo against a per-user config root
- Ensure MULTICA_TASK_CONFIG_ROOT directories are owned by the user running the CLI
- Check file ownership after any privileged invocation that touches ~/.multica
When it happens
Trigger: Calling LoadCLIConfig()/LoadCLIConfigForProfile(profile) when the config file exists but the process lacks read permission (root-owned file after running the CLI with sudo, or MULTICA_TASK_CONFIG_ROOT pointing at a directory chmod'd 0700 owned by another user), or when the path names a directory.
Common situations: Running the CLI once with sudo so ~/.multica/profiles/<name>/config.json becomes root-owned; a task-local root under MULTICA_TASK_CONFIG_ROOT created by a daemon running as a different user; a stray directory named config.json.
Related errors
- create CLI config directory: %w
- mint PAT: target API URL not set
- mint PAT: response missing token
- daemon profile is not resolved yet; token sync skipped
- runtime local skill discovery timed out
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/62bd3510354db33a.
Report an issue: GitHub.