chenhg5/cc-connect · error

create temp file: %w

Error message

create temp file: %w

What it means

When the formatted TOML differs from the input, FormatConfigFile writes atomically via a .config-*.tmp file created with os.CreateTemp in the file's directory. CreateTemp failure (unwritable directory, missing dir, full disk) is wrapped as "create temp file: %w" and the original file is left unchanged.

Source

Thrown at config/config.go:3717

// FormatConfigFile reads the config file at the given path, formats it, and
// writes it back. It validates the TOML syntax before writing.
func FormatConfigFile(path string) error {
	data, err := os.ReadFile(path)
	if err != nil {
		return fmt.Errorf("read config: %w", err)
	}
	cfg := &Config{}
	if err := toml.Unmarshal(data, cfg); err != nil {
		return fmt.Errorf("invalid TOML: %w", err)
	}
	formatted := formatTOML(string(data))
	if formatted == string(data) {
		return nil
	}
	dir := filepath.Dir(path)
	tmp, err := os.CreateTemp(dir, ".config-*.tmp")
	if err != nil {
		return fmt.Errorf("create temp file: %w", err)
	}
	tmpPath := tmp.Name()
	if _, err := tmp.WriteString(formatted); err != nil {
		tmp.Close()
		os.Remove(tmpPath)
		return fmt.Errorf("write formatted config: %w", err)
	}
	if err := tmp.Sync(); err != nil {
		tmp.Close()
		os.Remove(tmpPath)
		return err
	}
	if err := tmp.Close(); err != nil {
		os.Remove(tmpPath)
		return err
	}
	return os.Rename(tmpPath, path)
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Ensure the directory containing the config is writable by the current user (`ls -ld <dir>`).
  2. Run with elevated permissions when formatting system-wide configs (e.g. sudo for /etc paths).
  3. Free disk space if the filesystem is full.

Example fix

// before (shell)
cc-connect config format /etc/cc-connect/config.toml   # EACCES on temp file
// after
sudo cc-connect config format /etc/cc-connect/config.toml
Defensive patterns

Strategy: try-catch

Validate before calling

dir := filepath.Dir(path)
info, err := os.Stat(dir)
if err != nil || !info.IsDir() {
    return fmt.Errorf("config dir missing: %s", dir)
}
probe, err := os.CreateTemp(dir, ".fmt-probe-*")
if err != nil {
    return fmt.Errorf("dir not writable: %w", err)
}
probe.Close(); os.Remove(probe.Name())

Try / catch

if err := config.FormatConfigFile(path); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && strings.Contains(err.Error(), "create temp file") && errors.Is(pe.Err, fs.ErrPermission) {
        return fmt.Errorf("need write access to %s (try sudo)", filepath.Dir(path))
    }
    return err
}

Prevention

When it happens

Trigger: os.CreateTemp(filepath.Dir(path), ".config-*.tmp") fails in FormatConfigFile (config/config.go:3717): the target directory is read-only, was deleted, or the filesystem is out of space/inodes.

Common situations: Formatting a config in /etc or a read-only mount without elevated privileges; tmpfs full; directory removed by another process between read and write.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/7813c68ebb63bb39. Report an issue: GitHub.