multica-ai/multica · error

parse CLI config: %w

Error message

parse CLI config: %w

What it means

The config file at the profile path was read successfully but json.Unmarshal could not decode it into CLIConfig. The wrapped error identifies the JSON syntax error and its byte offset. A missing file is treated as an empty config, so this only happens with present-but-invalid content.

Source

Thrown at server/internal/cli/config.go:306

	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 err
	}
	dir := filepath.Dir(path)
	dirMode := os.FileMode(0o755)
	if strings.TrimSpace(os.Getenv(TaskConfigRootEnv)) != "" {

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Open the file named in the path resolution and fix the JSON syntax error indicated by the offset in the wrapped message
  2. If the file is corrupt beyond repair, delete or rename it — the loader treats a missing file as a fresh empty config
  3. Re-save a known-good config via the CLI's own config set/save command so future writes are atomic
  4. If a field type changed after an upgrade, rewrite the values to match the current schema or start from the empty config

Example fix

// before: ~/.multica/profiles/dev/config.json
{"default_workspace": "acme",}

// after
{"default_workspace": "acme"}
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(path)
if err == nil {
	if !json.Valid(data) {
		// quarantine the bad file and start from an empty config
		os.Rename(path, path+".invalid")
	}
}

Type guard

func isConfigParseErr(err error) bool {
	var syn *json.SyntaxTypeError
	return err != nil && (strings.Contains(err.Error(), "parse CLI config:") || errors.As(err, &syn))
}

Try / catch

cfg, err := cli.LoadCLIConfigForProfile(profile)
if err != nil {
	var synErr *json.SyntaxError
	if errors.As(err, &synErr) {
		// offer to reset the config: delete the file so the next load is empty
	}
	return err
}

Prevention

When it happens

Trigger: Calling LoadCLIConfig()/LoadCLIConfigForProfile when config.json contains truncated JSON (a crashed atomic write), hand-edited JSON with a trailing comma, or an object whose fields changed type between CLI versions.

Common situations: Editing ~/.multica/config.json by hand and introducing a syntax error; a killed process leaving a partially written file despite the temp-file rename; schema drift after upgrading the CLI to a version with different field types.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/2f84b584748d285b. Report an issue: GitHub.