charmbracelet/glow · error

could not write configuration file: %w

Error message

could not write configuration file: %w

What it means

ensureConfigFile, when --config was not passed, takes configFile from viper.GetViper().ConfigFileUsed() and immediately does os.MkdirAll(filepath.Dir(configFile), 0o755) to make sure the parent directory exists. This error wraps that MkdirAll failure. It fires before extension checks or file creation, so it is about the directory, not the file.

Source

Thrown at config_cmd.go:60

			return fmt.Errorf("unable to set config file: %w", err)
		}
		c.Stdin = os.Stdin
		c.Stdout = os.Stdout
		c.Stderr = os.Stderr
		if err := c.Run(); err != nil {
			return fmt.Errorf("unable to run command: %w", err)
		}

		fmt.Println("Wrote config file to:", configFile)
		return nil
	},
}

func ensureConfigFile() error {
	if configFile == "" {
		configFile = viper.GetViper().ConfigFileUsed()
		if err := os.MkdirAll(filepath.Dir(configFile), 0o755); err != nil { //nolint:gosec
			return fmt.Errorf("could not write configuration file: %w", err)
		}
	}

	if ext := path.Ext(configFile); ext != ".yaml" && ext != ".yml" {
		return fmt.Errorf("'%s' is not a supported configuration type: use '%s' or '%s'", ext, ".yaml", ".yml")
	}

	if _, err := os.Stat(configFile); errors.Is(err, fs.ErrNotExist) {
		// File doesn't exist yet, create all necessary directories and
		// write the default config file
		if err := os.MkdirAll(filepath.Dir(configFile), 0o700); err != nil {
			return fmt.Errorf("unable create directory: %w", err)
		}

		f, err := os.Create(configFile)
		if err != nil {
			return fmt.Errorf("unable to create config file: %w", err)
		}

View on GitHub (pinned to e3970c813d)

Solutions

  1. Check ownership and permissions of the config dir: ls -ld ~/.config ~/.config/glow
  2. Take ownership: sudo chown -R $USER ~/.config
  3. Point elsewhere: glow config --config /tmp/glow.yml (on a writable path)
  4. Verify XDG_CONFIG_HOME/HOME are set to writable locations

Example fix

# before
$ glow config
# Error: could not write configuration file: mkdir /home/user/.config/glow: permission denied

# after
$ sudo chown -R "$USER" ~/.config && glow config
Defensive patterns

Strategy: validation

Validate before calling

func ensureConfigDirWritable(cfgPath string) error {
	dir := filepath.Dir(cfgPath)
	if err := os.MkdirAll(dir, 0o755); err != nil {
		return fmt.Errorf("config dir %s unusable: %w", dir, err)
	}
	if !isWritable(dir) {
		return fmt.Errorf("config dir %s is not writable by uid %d", dir, os.Getuid())
	}
	return nil
}

func isWritable(dir string) bool {
	f, err := os.CreateTemp(dir, ".glow-probe-*")
	if err != nil {
		return false
	}
	_ = f.Close()
	_ = os.Remove(f.Name())
	return true
}

Try / catch

if err := ensureConfigFile(); err != nil {
	if strings.Contains(err.Error(), "could not write configuration file") {
		// directory-level failure: report ownership hint instead of retrying blindly
		fmt.Fprintf(os.Stderr, "fix perms on %s (chown -R $USER) or pass --config elsewhere\n", filepath.Dir(configFile))
		os.Exit(1)
	}
	return err
}

Prevention

When it happens

Trigger: The resolved config directory cannot be created or written: permission denied on an existing parent (e.g. ~/.config owned by root); the path component exists as a regular file; read-only filesystem or full disk; XDG_CONFIG_HOME pointing somewhere unwritable; ConfigFileUsed() returning an empty/unexpected value so Dir() resolves oddly.

Common situations: Running glow as a different user than the home owner after files were created with sudo; containers with a read-only /root; HOME unset so the config path collapses; disk quota exhausted.

Related errors


AI-assisted analysis of charmbracelet/glow@e3970c813d (2026-08-15). Data as JSON: /api/errors/3898e4f445564579. Report an issue: GitHub.