cloudflare/cloudflared · error

error writing %s: %v

Error message

error writing %s: %v

What it means

This error is returned by ServiceTemplate.Generate when os.WriteFile fails to write the rendered template buffer to the resolved path (e.g. the launchd plist file). The directory was created successfully, but the final file write failed — typically due to permissions, disk-full, or the destination being a directory. The message includes the resolved file path.

Source

Thrown at cmd/cloudflared/service_template.go:66

	var buffer bytes.Buffer
	err = tmpl.Execute(&buffer, args)
	if err != nil {
		return fmt.Errorf("error generating %s: %v", st.Path, err)
	}
	fileMode := os.FileMode(0o644)
	if st.FileMode != 0 {
		fileMode = st.FileMode
	}

	plistFolder := filepath.Dir(resolvedPath)
	err = os.MkdirAll(plistFolder, 0o755)
	if err != nil {
		return fmt.Errorf("error creating %s: %v", plistFolder, err)
	}

	err = os.WriteFile(resolvedPath, buffer.Bytes(), fileMode)
	if err != nil {
		return fmt.Errorf("error writing %s: %v", resolvedPath, err)
	}
	return nil
}

func (st *ServiceTemplate) Remove() error {
	resolvedPath, err := st.ResolvePath()
	if err != nil {
		return err
	}
	err = os.Remove(resolvedPath)
	if err != nil {
		return fmt.Errorf("error deleting %s: %v", resolvedPath, err)
	}
	return nil
}

func serviceAlreadyExistsWarn(service string) string {
	return fmt.Sprintf("cloudflared service is already installed at %s; if you are running a cloudflared tunnel, you "+

View on GitHub (pinned to 2253eeeb25)

Solutions

  1. Re-run the install with sudo so the plist is writable
  2. Check the destination path is not an existing directory or immutable file and remove/fix it if stale: ls -laO /Library/LaunchDaemons/com.cloudflare.cloudflared.plist
  3. Verify free disk space (df -h) and writable system volume
  4. Check MDM/endpoint-security software isn't blocking writes to LaunchDaemons

Example fix

// before
$ cloudflared service install  // open /Library/LaunchDaemons/...: permission denied
// after
$ sudo cloudflared service install
Defensive patterns

Strategy: try-catch

Validate before calling

if fi, err := os.Stat(resolvedPath); err == nil && fi.IsDir() {
	return fmt.Errorf("%s exists as a directory; remove it before installing", resolvedPath)
}
if err := unix.Access(filepath.Dir(resolvedPath), unix.W_OK); err != nil {
	return errors.New("insufficient permission to write service file; run with sudo")
}

Type guard

func canWriteFile(path string) bool {
	dir := filepath.Dir(path)
	f, err := os.CreateTemp(dir, ".probe")
	if err != nil { return false }
	n := f.Name()
	_ = f.Close()
	_ = os.Remove(n)
	return true
}

Try / catch

if err := st.Generate(args); err != nil {
	if strings.Contains(err.Error(), "error writing") {
		if strings.Contains(err.Error(), "permission denied") {
			// re-run with sudo
		} else if strings.Contains(err.Error(), "no space left") {
			// free disk space and retry
		}
	}
	return err
}

Prevention

When it happens

Trigger: Calling Generate() (via installLaunchd) where os.WriteFile(resolvedPath, buffer.Bytes(), fileMode) returns an error: EACCES on a read-only or root-owned directory, ENOSPC disk full, or resolvedPath exists as a directory.

Common situations: Installing the service without sudo so /Library/LaunchDaemons is not writable; an existing stale plist with immutable attribute or wrong ownership; disk exhaustion on the system volume; antivirus/MDM blocking writes to LaunchDaemons.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06). Data as JSON: /api/errors/7e297929a4e1a7c6. Report an issue: GitHub.