cloudflare/cloudflared · error
error removing %s: %w
Error message
error removing %s: %w
What it means
After resolving the OpenRC template paths, uninstallOpenRC calls os.Remove on each service file. This error is returned when os.Remove fails for any reason other than the file not existing (ErrNotExist is deliberately tolerated so uninstall is idempotent). It signals a real filesystem obstacle such as missing permissions or the path being a non-empty directory.
Source
Thrown at cmd/cloudflared/linux_service.go:548
}
}
return nil
}
func uninstallOpenRC(log *zerolog.Logger) error {
if err := runCommand("rc-service", cloudflaredOpenRCService, "stop"); err != nil {
log.Warn().Err(err).Msg("could not stop cloudflared OpenRC service, continuing uninstall")
}
if err := runCommand("rc-update", "del", cloudflaredOpenRCService, "default"); err != nil {
log.Warn().Err(err).Msg("could not remove cloudflared from the default runlevel, continuing uninstall")
}
for _, template := range []ServiceTemplate{openrcTemplate, openrcConfTemplate} {
path, err := template.ResolvePath()
if err != nil {
return fmt.Errorf("error resolving OpenRC template path: %w", err)
}
if err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("error removing %s: %w", path, err)
}
}
return nil
}
func copyFile(src, dest string) error {
srcFile, err := os.Open(src) //nolint:gosec // operator-provided service config path
if err != nil {
return err
}
defer func() { _ = srcFile.Close() }()
destFile, err := os.Create(dest) //nolint:gosec // operator-provided service config path
if err != nil {
return err
}
ok := false
defer func() {View on GitHub (pinned to 2253eeeb25)
Solutions
- Re-run with root privileges: `sudo cloudflared service uninstall`
- Check and clear the immutable flag if set: `lsattr /etc/init.d/cloudflared; sudo chattr -i /etc/init.d/cloudflared`
- If the filesystem is read-only, remount rw (`mount -o remount,rw /etc` or boot normally) and retry
- Remove manually after fixing permissions: `sudo rm -f /etc/init.d/cloudflared /etc/conf.d/cloudflared`
- Check the wrapped (%w) error for the exact errno (EACCES vs EISDIR etc.) to pick the right fix
Example fix
// before: non-root uninstall $ cloudflared service uninstall // error: error removing /etc/init.d/cloudflared: remove /etc/init.d/cloudflared: permission denied // after $ sudo cloudflared service uninstall
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check writability before uninstall
func ensureRemovable(path string) error {
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil // nothing to remove
}
if err := syscall.Access(filepath.Dir(path), unix.W_OK); err != nil {
return fmt.Errorf("cannot remove %s: need write access to %s (run as root): %w", path, filepath.Dir(path), err)
}
return nil
} Type guard
func fileRemovable(path string) bool {
fi, err := os.Stat(path)
if err != nil { return os.IsNotExist(err) } // absent = fine
return !fi.IsDir() && fi.Mode().Perm()&0o200 != 0 || os.Geteuid() == 0
} Try / catch
if err := uninstallLinuxService(c); err != nil {
if strings.Contains(err.Error(), "error removing") {
log.Warn("file removal blocked; check root privileges, read-only /etc, immutable flags (chattr -i), or SELinux denials")
}
return err
} Prevention
- Run uninstall as root; /etc is writable only by root on most systems
- Check for immutable flags (lsattr/chattr -i) on /etc/init.d/cloudflared if removal fails with EPERM as root
- Ensure /etc is not mounted read-only (containers, recovery mode) before uninstalling
- Check SELinux/AppArmor audit logs if permission is denied despite root
When it happens
Trigger: During `cloudflared service uninstall` on OpenRC, when os.Remove(path) on /etc/init.d/cloudflared or /etc/conf.d/cloudflared fails with EACCES/EPERM (not root, read-only filesystem, immutable file) or EISDIR/ENOTEMPTY (path is a directory).
Common situations: Running uninstall without sudo; /etc mounted read-only (recovery mode, immutable container image); file or parent directory marked immutable (chattr +i); SELinux/AppArmor denial on removing init scripts; leftover directory where the file used to be.
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
- error resolving OpenRC template path: %w
- could not write token to configuration directory: %w
- error generating OpenRC conf.d template: %w
- error generating OpenRC service template: %w
- rc-update add %s default: %w
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/9d27e94c4d944038.
Report an issue: GitHub.