VictoriaMetrics/VictoriaMetrics · error

cannot open %q: %w

Error message

cannot open %q: %w

What it means

DeletePath failed to open the file for deletion. Missing files (ENOENT) are treated as success (already deleted via symlink), but any other open error — permission, I/O, or a path that is a directory without proper access — is wrapped in this error and stops the deletion.

Source

Thrown at lib/backup/fslocal/fslocal.go:228

		return nil
	})
}

// DeletePath deletes the given path from fs and returns the size for the deleted file.
//
// The path must be in canonical form, e.g. it must have `/` directory separators
func (fs *FS) DeletePath(path string) (uint64, error) {
	p := common.Part{
		Path: path,
	}
	fullPath := fs.path(p)
	f, err := os.Open(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			// The file could be deleted earlier via symlink.
			return 0, nil
		}
		return 0, fmt.Errorf("cannot open %q: %w", path, err)
	}
	fi, err := f.Stat()
	_ = f.Close()
	if err != nil {
		return 0, fmt.Errorf("cannot stat %q at %q: %w", path, fullPath, err)
	}
	size := uint64(fi.Size())
	if err := os.Remove(fullPath); err != nil {
		return 0, fmt.Errorf("cannot remove %q: %w", fullPath, err)
	}
	return size, nil
}

// RemoveEmptyDirs recursively removes all the empty directories in fs.
func (fs *FS) RemoveEmptyDirs() error {
	return fscommon.RemoveEmptyDirs(fs.Dir)
}

View on GitHub (pinned to 5079fb58f1)

Solutions

  1. Read the wrapped errno: EACCES/EPERM — fix ownership/permissions (chown -R) so the deleting user can open the file; ELOOP — remove the symlink cycle
  2. Check for immutable attributes: lsattr / chattr -i on the affected path
  3. Verify the mount is healthy (dmesg) if EIO is reported, then retry the deletion
  4. Run deletion as the same user that owns the backup directory

Example fix

// before: files owned by root after a manual restore
// after:
sudo chown -R victoria-metrics:victoria-metrics /var/lib/victoria-metrics
sudo chattr -i /var/lib/victoria-metrics/data/... # if immutable
Defensive patterns

Strategy: try-catch

Validate before calling

// before deleting, verify the path is openable by the current user
full := filepath.Join(fs.Dir, filepath.FromSlash(canonicalPath))
f, err := os.Open(full)
if err != nil {
    if !os.IsNotExist(err) { return fmt.Errorf("pre-delete check failed: %w", err) }
} else { f.Close() }
// also check write permission on parent dir (unlink requirement)
if err := unix.Access(filepath.Dir(full), unix.W_OK); err != nil {
    return fmt.Errorf("no write perm on parent dir: %w", err)
}

Try / catch

n, err := fs.DeletePath(path)
if err != nil {
    var pe *os.PathError
    if errors.As(err, &pe) && (errors.Is(pe.Err, syscall.EACCES) || errors.Is(pe.Err, syscall.EPERM)) {
        return fmt.Errorf("fix ownership/permissions for %s: %w", path, err)
    }
    return err
}

Prevention

When it happens

Trigger: os.Open(fullPath) fails with a non-IsNotExist error while deleting canonical path `path` under fs.Dir: EACCES/EPERM on the file or a parent directory, EIO from storage, or ELOOP from a symlink cycle.

Common situations: Files created by a different user (root) inside the data dir while deletion runs as a service user; immutable flags (chattr +i) on old backup parts; broken mounts returning I/O errors; permission drift after restore-as-root.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03). Data as JSON: /api/errors/e211f4fe90406801. Report an issue: GitHub.