multica-ai/multica · error

create CLI config directory: %w

Error message

create CLI config directory: %w

What it means

SaveCLIConfigForProfile could not create the profile directory tree (~/.multica/profiles/<name> or its task-local equivalent) with os.MkdirAll. The wrapped errno is usually EACCES or ENOTDIR. This is the first write-path step, before any file is produced.

Source

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

// 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)) != "" {
		dirMode = 0o700
	}
	if err := os.MkdirAll(dir, dirMode); err != nil {
		return fmt.Errorf("create CLI config directory: %w", err)
	}
	if dirMode == 0o700 {
		root, _, err := multicaConfigRoot()
		if err != nil {
			return fmt.Errorf("resolve task-local CLI config root: %w", err)
		}
		for current := dir; ; current = filepath.Dir(current) {
			if err := os.Chmod(current, 0o700); err != nil {
				return fmt.Errorf("restrict task-local CLI config directory: %w", err)
			}
			if current == root {
				break
			}
			parent := filepath.Dir(current)
			if parent == current {
				return fmt.Errorf("task-local CLI config directory %q escapes root %q", dir, root)
			}
		}

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Check the exact path from the wrapped error; ensure every existing component is a directory and owned/writable by the current user
  2. chown -R $(whoami) the config root if a sudo run changed ownership
  3. Remove any plain file blocking a directory component (e.g. rm ~/.multica/profiles if it is a file)
  4. Free disk space or remount the home directory read-write if that is the underlying errno

Example fix

# before
$ multica config set default_workspace acme
create CLI config directory: mkdir /home/user/.multica/profiles: permission denied

# after
$ sudo chown -R $(whoami) ~/.multica
$ multica config set default_workspace acme
Defensive patterns

Strategy: validation

Validate before calling

dir := filepath.Dir(configPath)
if info, err := os.Stat(filepath.Dir(dir)); err == nil && !info.IsDir() {
	// a file occupies a parent component; fail early with a clear message
}

Try / catch

if err := cli.SaveCLIConfig(cfg); err != nil {
	if errors.Is(err, os.ErrPermission) || strings.Contains(err.Error(), "create CLI config directory") {
		// guide the user to fix ownership of the config root
	}
	return err
}

Prevention

When it happens

Trigger: Calling SaveCLIConfig/SaveCLIConfigForProfile when the home directory or an ancestor of the target path is read-only, when a non-directory file occupies a path component (e.g. a file named 'profiles'), or when permissions deny creation.

Common situations: Home dir mounted read-only or full (ENOSPC surfaces similarly); earlier root-run invocation created ~/.multica as root:root 755 so the normal user cannot add subdirectories; MULTICA_TASK_CONFIG_ROOT pointing into a path where a component is a plain file.

Related errors


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