googleapis/mcp-toolbox · critical

failed to restore original file: %w

Error message

failed to restore original file: %w

What it means

This is the secondary error raised when BOTH the write of migrated content failed (error 47) AND the automatic restore (`os.Rename(backupFile, filePath)`) also failed. It is joined with the write error via `errors.Join`, so the reported message contains the original write failure plus 'failed to restore original file'. At this point the original content lives only in `<filePath>.bak` and the target path may be missing or hold a partial file, making this the most dangerous state the migrate command can produce.

Source

Thrown at cmd/internal/migrate/command.go:119

			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 nil
	return errors.Join(errs...)
}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Immediately recover manually: `mv <filePath>.bak <filePath>` — the original content is in the .bak.
  2. If `.bak` is missing, restore the file from version control or backups; never leave a partial file in place.
  3. Fix the root environmental cause (free disk space, remount read-write, fix permissions) before re-running migrate.
  4. Avoid concurrent processes touching the same paths during migrate (lock or stop other tooling).
  5. Re-run migrate and confirm the error list is empty.

Example fix

// before: assuming .bak always exists
// after: verify and restore defensively before re-running
if _, err := os.Stat("config.yaml.bak"); err == nil {
    if err := os.Rename("config.yaml.bak", "config.yaml"); err != nil {
        log.Fatalf("manual restore failed: %v", err)
    }
}
Defensive patterns

Strategy: fallback

Validate before calling

before, err := os.ReadFile(filePath)
if err != nil { return err }
if err := os.WriteFile(filePath+".pre-migrate-copy", before, 0o600); err != nil {
    return fmt.Errorf("cannot create safety copy: %v", err)
}

Try / catch

defer func() {
    if r := recover(); r != nil || failed {
        if _, err := os.Stat(path + ".bak"); err == nil {
            _ = os.Remove(path)            // drop partial file
            if rErr := os.Rename(path+".bak", path); rErr != nil {
                log.Fatalf("CRITICAL: could not restore %s from .bak: %v", path, rErr)
            }
        }
    }
}()

Prevention

When it happens

Trigger: After a failed os.WriteFile, the cleanup os.Remove(filePath) or the restore os.Rename(backupFile, filePath) fails — e.g. the directory became non-writable, the .bak was concurrently deleted, or the .bak itself sits on a failing filesystem. Any condition causing the initial failure usually also causes the restore to fail.

Common situations: Disk full: both write and restore fail; the file is left missing with only `file.bak` present. Container volume switched to read-only mid-run. Another process (or a previous crashed run) already removed the .bak. NFS stale-handle errors after the server restarted.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/5be13388dc0223c3. Report an issue: GitHub.