JanDeDobbeleer/oh-my-posh · error

failed to write configuration file %s: %w

Error message

failed to write configuration file %s: %w

What it means

Configuration.Apply writes the exported config data with os.WriteFile; when that write fails, the error is wrapped with the target file path. The underlying syscall error (permission denied, disk full, target is a directory, read-only volume) is available via %w/errors.Unwrap or errors.As(*fs.PathError).

Source

Thrown at src/cli/dsc/config.go:96

		return fmt.Errorf("source file %s does not match format %s", c.Source, c.Format)
	}

	log.Debug("Applying configuration %s", c.Source)

	// Expand tilde to home directory for file operations
	filePath := strings.ReplaceAll(c.Source, "~", path.Home())

	// Create directory if it doesn't exist
	dir := filepath.Dir(filePath)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("failed to create directory %s: %w", dir, err)
	}

	data := c.Export(c.Format)

	// Write file
	if err := os.WriteFile(filePath, []byte(data), 0644); err != nil {
		return fmt.Errorf("failed to write configuration file %s: %w", filePath, err)
	}

	log.Debug("Configuration written to %s", filePath)
	return nil
}

func (c *Configuration) Equal(other *Configuration) bool {
	if other == nil {
		return false
	}

	return c.Source == other.Source
}

func (c *Configuration) Resolve() (*Configuration, bool) {
	log.Debug("Resolving configuration %s", c.Source)

	if c.resolved {

View on GitHub (pinned to 0976794618)

Solutions

  1. Check the wrapped error and the path in the message: confirm the path is a file, not a directory, and that you have write permission
  2. Fix ownership/permissions (chown/chmod) or delete the read-only/locked file so WriteFile can recreate it
  3. Free disk space if the error indicates the volume is full
  4. Run elevated only if the destination genuinely requires it; otherwise point Source at a user-writable location

Example fix

// before: file owned by root
-rw-r--r-- root root ~/.config/oh-my-posh/config.omp.json
// after
sudo chown $USER ~/.config/oh-my-posh/config.omp.json
Defensive patterns

Strategy: validation

Validate before calling

target := strings.ReplaceAll(source, "~", home)
if st, err := os.Stat(target); err == nil && st.IsDir() {
    return fmt.Errorf("%s is a directory, expected a file", target)
}
if st, err := os.Stat(target); err == nil {
    f, err := os.OpenFile(target, os.O_WRONLY, 0)
    if err != nil { return fmt.Errorf("cannot write %s: %w", target, err) }
    f.Close()
}

Try / catch

if err := cfg.Apply(); err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) {
        switch {
        case errors.Is(perr.Err, fs.ErrPermission):
            return fmt.Errorf("fix permissions or ownership of %s", perr.Path)
        case errors.Is(perr.Err, syscall.ENOSPC):
            return fmt.Errorf("disk full: free space and retry")
        }
    }
    return err
}

Prevention

When it happens

Trigger: Applying a DSC Configuration where the destination path exists as a directory, the user lacks write permission on the file or its directory, or the filesystem is read-only/full.

Common situations: Config file previously created by root so a normal user cannot overwrite it; Windows file locked by another process; overwriting a read-only file; destination path accidentally points at a directory name.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31). Data as JSON: /api/errors/c4de1c25ed02f67c. Report an issue: GitHub.