googleapis/mcp-toolbox · error
failed to write to file: %w
Error message
failed to write to file: %w
What it means
Thrown when `os.WriteFile(filePath, newBuf, info.Mode().Perm())` fails after the original file was already renamed to `.bak`. runMigrate then attempts an automatic restore: it removes the possibly partial file and renames the `.bak` back to the original path, joining any secondary errors into one message. The file's original permissions are preserved via the saved mode, so the failure is typically environmental (disk full, permissions, I/O error) rather than a code bug.
Source
Thrown at cmd/internal/migrate/command.go:113
errMsg := fmt.Errorf("failed to stat file: %w", err)
logger.ErrorContext(ctx, errMsg.Error())
errs = append(errs, errMsg)
continue
}
backupFile := filePath + ".bak"
err = os.Rename(filePath, backupFile)
if err != nil {
errMsg := fmt.Errorf("failed to rename file: %w", err)
logger.ErrorContext(ctx, errMsg.Error())
errs = append(errs, errMsg)
continue
}
logger.DebugContext(ctx, fmt.Sprintf("successfully renamed %s to %s", filePath, backupFile))
// set the permission to the original file's permission.
err = os.WriteFile(filePath, newBuf, info.Mode().Perm())
if err != nil {
errMsg := fmt.Errorf("failed to write to file: %w", err)
// restoring original file
if removeErr := os.Remove(filePath); removeErr != nil { // Attempt to remove the possibly partial file to ensure Rename succeeds.
errMsg = errors.Join(errMsg, removeErr)
}
if restoreErr := os.Rename(backupFile, filePath); restoreErr != nil {
fullRestoreErr := fmt.Errorf("failed to restore original file: %w", restoreErr)
errMsg = errors.Join(errMsg, fullRestoreErr)
}
logger.ErrorContext(ctx, errMsg.Error())
errs = append(errs, errMsg)
continue
}
logger.DebugContext(ctx, fmt.Sprintf("migration completed for file: %s", filePath))
}
}
logger.InfoContext(ctx, "migration ended!")
// If errs is empty, errors.Join returns nilView on GitHub (pinned to 8cc6e09de2)
Solutions
- Free disk space or increase the volume/quota, then re-run migrate (the original file was restored from `.bak`, so it is safe to retry).
- Check for a leftover `.bak` next to the file; if the file content looks wrong, manually `mv file.bak file` to restore and investigate.
- Verify the effective user can write to the directory (`touch <dir>/.probe`) and adjust chown/chmod or run with elevated privileges.
- Check `dmesg`/journal for I/O errors on the backing device; move the file to healthy storage and retry.
- If SELinux is enforcing, check `audit.log` for denials and relabel with `restorecon`.
Example fix
// before: blind retry after disk-full
err = os.WriteFile(filePath, newBuf, info.Mode().Perm())
// after: check free space before rewriting
if st, serr := os.Statfs(dir); serr == nil && st.Bavail*uint64(st.Bsize) < uint64(len(newBuf)) {
return fmt.Errorf("insufficient space in %s: need %d bytes", dir, len(newBuf))
}
err = os.WriteFile(filePath, newBuf, info.Mode().Perm()) Defensive patterns
Strategy: try-catch
Validate before calling
if st, err := syscall.Statfs(dir); err == nil && uint64(st.Bavail)*uint64(st.Bsize) < minBytesNeeded {
return fmt.Errorf("not enough free space in %s", dir)
} Try / catch
info, err := os.Stat(path)
if err != nil { return err }
if err := os.WriteFile(path, buf, info.Mode().Perm()); err != nil {
// migrate already restores from .bak; verify the original is intact
if _, statErr := os.Stat(path); statErr != nil {
if bak, bErr := os.Stat(path + ".bak"); bErr == nil && bak.Size() > 0 {
_ = os.Rename(path+".bak", path)
}
}
return fmt.Errorf("write failed for %s: %w", path, err)
} Prevention
- Keep headroom on the filesystem; monitor disk usage in CI runners.
- Always keep the `.bak` until you have diffed and validated the migrated file.
- Run migrate as the file owner so permission context is consistent between rename and write.
- Avoid NFS/network volumes for migrate targets when possible; prefer local disk.
- Re-run migrate only after confirming the original file content was restored.
When it happens
Trigger: Writing the migrated content fails because the disk is out of space, the user lacks write permission (though rename succeeded, the new file may inherit different context), an I/O error occurs (EIO), or a quota is exceeded. Also fires if the target file was recreated by a concurrent process with restrictive permissions.
Common situations: Migrating a large config on a nearly-full container overlay filesystem; running in CI where the workspace volume enforces quotas; SELinux/AppArmor denying write to the recreated file; NFS server hiccup causing EIO mid-write.
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
- failed to stat file: %w
- failed to rename file: %w
- failed to restore original file: %w
- error finding YAML files in %q: %w
- error finding YML files in %q: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/580e91c60338803d.
Report an issue: GitHub.