tailscale/tailscale · error
failed writing systemd user service: %w
Error message
failed writing systemd user service: %w
What it means
Returned by installSystemd when os.WriteFile fails writing the generated unit to <configDir>/systemd/user/tailscale-systray.service with mode 0755. By this point the ExecStart= line has already been rewritten to the resolved tailscale binary path plus 'systray'. The write is the last step before the success message, so failure here leaves no partial unit on disk (WriteFile is atomic-ish: it truncates then writes).
Source
Thrown at client/systray/startup-creator.go:80
configDir, err := os.UserConfigDir()
if err != nil {
homeDir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("unable to locate user home: %w", err)
}
configDir = filepath.Join(homeDir, ".config")
}
systemdDir := filepath.Join(configDir, "systemd", "user")
if err := os.MkdirAll(systemdDir, 0o755); err != nil {
return fmt.Errorf("failed creating systemd user dir: %w", err)
}
serviceFile := filepath.Join(systemdDir, "tailscale-systray.service")
if err := os.WriteFile(serviceFile, output.Bytes(), 0o755); err != nil {
return fmt.Errorf("failed writing systemd user service: %w", err)
}
fmt.Printf("Successfully installed systemd service to: %s\n", serviceFile)
fmt.Println("To enable and start the service, run:")
fmt.Println(" systemctl --user daemon-reload")
fmt.Println(" systemctl --user enable --now tailscale-systray")
return nil
}
func installFreedesktop() error {
tmpDir, err := os.MkdirTemp("", "tailscale-systray")
if err != nil {
return fmt.Errorf("unable to make tmpDir: %w", err)
}
defer os.RemoveAll(tmpDir)
// Install icon, and use it if it works, and if not change to some genericView on GitHub (pinned to cfe32b8be6)
Solutions
- If a root-owned service file exists from an earlier sudo run, remove or chown it: sudo rm ~/.config/systemd/user/tailscale-systray.service.
- Confirm the directory is writable by the current user (ls -ld ~/.config/systemd/user).
- Free disk space if the write fails with a no-space error.
- Prefer running the installer as the same user that will own the systemd --user unit.
Example fix
# before $ ./tailscale-systray-setup failed writing systemd user service: ... permission denied # after $ ls -l ~/.config/systemd/user/tailscale-systray.service -rwxr-xr-x 1 root root ... tailscale-systray.service $ sudo rm ~/.config/systemd/user/tailscale-systray.service $ ./tailscale-systray-setup
Defensive patterns
Strategy: try-catch
Validate before calling
svc := filepath.Join(configDir, "systemd", "user", "tailscale-systray.service")
if fi, err := os.Stat(svc); err == nil && fi.Mode().Perm() != 0o755 {
// possible root-owned leftover: remove before reinstall
} Type guard
func isPermissionErr(err error) bool { return errors.Is(err, fs.ErrPermission) } Try / catch
if err := systray.InstallStartupScript("systemd"); err != nil {
if errors.Is(err, fs.ErrPermission) && strings.Contains(err.Error(), "writing systemd") {
// remove root-owned unit file, then retry
}
} Prevention
- Always install as the user who will run the systemd --user unit.
- Clean stale unit files between reinstalls.
- Monitor disk space on the home filesystem.
When it happens
Trigger: An existing tailscale-systray.service owned by root (from a previous sudo install) that the current user cannot overwrite; read-only home filesystem; disk full; permission denial from mandatory access control on ~/.config/systemd/user.
Common situations: Re-running the installer as a normal user after a first run under sudo left root-owned files; systemd user unit directories under management (immutable/overlayfs); full disks in VMs.
Related errors
- failed to find tailscale binary %w
- failed creating systemd user dir: %w
- unable to create desktop file: %w
- API response too large
- unsupported init system '%s'
AI-assisted analysis of tailscale/tailscale@cfe32b8be6 (2026-08-15).
Data as JSON: /api/errors/033f36ce154c9522.
Report an issue: GitHub.