{"record":{"id":"580e91c60338803d","repo":"googleapis/mcp-toolbox","slug":"failed-to-write-to-file-w","errorCode":null,"errorMessage":"failed to write to file: %w","messagePattern":"failed to write to file: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/internal/migrate/command.go","lineNumber":113,"sourceCode":"\t\t\t\terrMsg := fmt.Errorf(\"failed to stat file: %w\", err)\n\t\t\t\tlogger.ErrorContext(ctx, errMsg.Error())\n\t\t\t\terrs = append(errs, errMsg)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tbackupFile := filePath + \".bak\"\n\t\t\terr = os.Rename(filePath, backupFile)\n\t\t\tif err != nil {\n\t\t\t\terrMsg := fmt.Errorf(\"failed to rename file: %w\", err)\n\t\t\t\tlogger.ErrorContext(ctx, errMsg.Error())\n\t\t\t\terrs = append(errs, errMsg)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlogger.DebugContext(ctx, fmt.Sprintf(\"successfully renamed %s to %s\", filePath, backupFile))\n\n\t\t\t// set the permission to the original file's permission.\n\t\t\terr = os.WriteFile(filePath, newBuf, info.Mode().Perm())\n\t\t\tif err != nil {\n\t\t\t\terrMsg := fmt.Errorf(\"failed to write to file: %w\", err)\n\t\t\t\t// restoring original file\n\t\t\t\tif removeErr := os.Remove(filePath); removeErr != nil { // Attempt to remove the possibly partial file to ensure Rename succeeds.\n\t\t\t\t\terrMsg = errors.Join(errMsg, removeErr)\n\t\t\t\t}\n\t\t\t\tif restoreErr := os.Rename(backupFile, filePath); restoreErr != nil {\n\t\t\t\t\tfullRestoreErr := fmt.Errorf(\"failed to restore original file: %w\", restoreErr)\n\t\t\t\t\terrMsg = errors.Join(errMsg, fullRestoreErr)\n\t\t\t\t}\n\t\t\t\tlogger.ErrorContext(ctx, errMsg.Error())\n\t\t\t\terrs = append(errs, errMsg)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlogger.DebugContext(ctx, fmt.Sprintf(\"migration completed for file: %s\", filePath))\n\t\t}\n\t}\n\n\tlogger.InfoContext(ctx, \"migration ended!\")\n\t// If errs is empty, errors.Join returns nil","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/cmd/internal/migrate/command.go#L95-L131","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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`."],"exampleFix":"// before: blind retry after disk-full\nerr = os.WriteFile(filePath, newBuf, info.Mode().Perm())\n// after: check free space before rewriting\nif st, serr := os.Statfs(dir); serr == nil && st.Bavail*uint64(st.Bsize) < uint64(len(newBuf)) {\n    return fmt.Errorf(\"insufficient space in %s: need %d bytes\", dir, len(newBuf))\n}\nerr = os.WriteFile(filePath, newBuf, info.Mode().Perm())","handlingStrategy":"try-catch","validationCode":"if st, err := syscall.Statfs(dir); err == nil && uint64(st.Bavail)*uint64(st.Bsize) < minBytesNeeded {\n    return fmt.Errorf(\"not enough free space in %s\", dir)\n}","typeGuard":null,"tryCatchPattern":"info, err := os.Stat(path)\nif err != nil { return err }\nif err := os.WriteFile(path, buf, info.Mode().Perm()); err != nil {\n    // migrate already restores from .bak; verify the original is intact\n    if _, statErr := os.Stat(path); statErr != nil {\n        if bak, bErr := os.Stat(path + \".bak\"); bErr == nil && bak.Size() > 0 {\n            _ = os.Rename(path+\".bak\", path)\n        }\n    }\n    return fmt.Errorf(\"write failed for %s: %w\", path, err)\n}","preventionTips":["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."],"tags":["go","filesystem","migrate","write","disk-full"],"backgroundTag":"file-write-failed","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}