golangci/golangci-lint · error
saving configuration file: %w
Error message
saving configuration file: %w
What it means
This error wraps any failure that occurs while writing the migrated (v2) configuration file to disk during `golangci-lint migrate`. The command converts a v1 config into the new format via `saveNewConfiguration`; if that helper fails (file creation, marshaling, or write error), it is wrapped with this message and returned to the caller. It is a shell error — the root cause is always the wrapped inner error.
Source
Thrown at pkg/commands/migrate.go:123
}
if !strings.EqualFold(filepath.Ext(srcPath), ext) {
defer func() {
_ = os.RemoveAll(srcPath)
}()
}
if c.cfg.Run.Timeout != 0 {
c.log.Warnf("The configuration `run.timeout` is ignored. By default, in v2, the timeout is disabled.")
}
newCfg := migrate.ToConfig(c.cfg)
dstPath := strings.TrimSuffix(srcPath, filepath.Ext(srcPath)) + ext
err = saveNewConfiguration(newCfg, dstPath)
if err != nil {
return fmt.Errorf("saving configuration file: %w", err)
}
c.log.Infof("Migration done: %s", dstPath)
callForAction(c.cmd)
return nil
}
func (c *migrateCommand) preRunE(cmd *cobra.Command, _ []string) error {
switch strings.ToLower(c.opts.format) {
case "", "yml", "yaml", "toml", "json":
// Valid format.
default:
return fmt.Errorf("unsupported format: %s", c.opts.format)
}
if c.cfg.Version != "" {View on GitHub (pinned to ed7a235d2d)
Solutions
- Read the wrapped error after this message to find the root cause (e.g. 'permission denied', 'no such file or directory').
- Ensure the migration output directory exists and is writable by the current user (chmod/chown or run from a writable copy).
- Copy the project (or just the config) to a writable location and run migrate there.
- If the file is locked, close the program holding it, then rerun migrate.
- Check disk space with `df -h` if the error indicates a full filesystem.
Example fix
// before golangci-lint migrate # run in a read-only CI checkout // after chmod u+w .golangci.yml && golangci-lint migrate # or run in a writable copy of the repo
Defensive patterns
Strategy: try-catch
Validate before calling
// Go: verify the migration destination is writable before running migrate
dst := strings.TrimSuffix(src, filepath.Ext(src)) + ".yml"
if f, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE, 0o644); err != nil {
return fmt.Errorf("destination %s not writable: %w", dst, err)
} else {
f.Close()
} Try / catch
if err := saveNewConfiguration(newCfg, dstPath); err != nil {
var pe *fs.PathError
if errors.As(err, &pe) {
log.Printf("write failed at %s: %v (op=%s)", pe.Path, pe.Err, pe.Op)
}
return fmt.Errorf("saving configuration file: %w", err)
} Prevention
- Run migrate from a writable working copy, never a read-only mount.
- Ensure the output directory exists before migrating.
- Avoid migrating configs inside locked editors or file-sync tools holding locks.
- Check disk space in CI runners before running migrations.
When it happens
Trigger: Running `golangci-lint migrate` when the destination path (source path with extension replaced) is not writable, e.g. the directory does not exist, permissions deny writing, the target file is locked/read-only, or serializing the new config to the requested format (yml/toml/json) fails.
Common situations: Running migrate in a read-only checkout or CI workspace; migrating a config in a directory the user cannot write to; a read-only mounted volume; the output file being open in an editor with a lock; an unsupported/invalid format value that passes validation but fails serialization.
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
- writing file %s: %w
- unsupported format: %s
- configuration version is already set: %s
- can't create file %s: %w
- create destination directory: %w
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/670ef1510b57a7c2.
Report an issue: GitHub.