spacedriveapp/spacedrive · error · anyhow::Error

Failed to load LaunchAgent: {}

Error message

Failed to load LaunchAgent: {}

What it means

After writing the plist to ~/Library/LaunchAgents, the installer runs `launchctl load <plist>` and requires exit status 0. If launchctl exits non-zero, its stderr is wrapped in this error. The plist is already on disk, so the failure is in the service manager, not in file generation.

Source

Thrown at apps/cli/src/domains/daemon/mod.rs:134

		stderr_log = stderr_log.display(),
		working_dir = home.display(),
	);

	// Write the plist file
	let mut file = fs::File::create(&plist_path)?;
	file.write_all(plist_content.as_bytes())?;

	println!("Created LaunchAgent: {}", plist_path.display());

	// Load the service
	let output = std::process::Command::new("launchctl")
		.arg("load")
		.arg(&plist_path)
		.output()?;

	if !output.status.success() {
		let stderr = String::from_utf8_lossy(&output.stderr);
		return Err(anyhow::anyhow!("Failed to load LaunchAgent: {}", stderr));
	}

	println!("Daemon installed successfully!");
	println!("The daemon will start automatically on login.");
	println!();
	println!("Logs:");
	println!("  stdout: {}", stdout_log.display());
	println!("  stderr: {}", stderr_log.display());

	Ok(())
}

#[cfg(target_os = "macos")]
async fn uninstall_launchd_service(instance: Option<String>) -> Result<()> {
	use std::fs;

	let home =
		dirs::home_dir().ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;

View on GitHub (pinned to 6dfeccf211)

Solutions

  1. Read the stderr embedded in the message; it names the exact launchctl failure.
  2. Run the install from a Terminal inside a normal GUI login session instead of SSH.
  3. Clear a stale registration first: `launchctl bootout gui/$(id -u)/com.spacedrive.daemon 2>/dev/null; rm ~/Library/LaunchAgents/com.spacedrive.daemon.plist`, then reinstall.
  4. If `load` keeps failing on newer macOS, load the written plist manually with the modern syntax: `launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.spacedrive.daemon.plist`.
  5. Validate the generated plist with `plutil -lint ~/Library/LaunchAgents/com.spacedrive.daemon.plist`.

Example fix

# before (over SSH, GUI domain missing)
sd-cli daemon install  # -> Failed to load LaunchAgent: Load failed: 5: Input/output error

# after (in a GUI login session, after clearing stale state)
launchctl bootout gui/$(id -u)/com.spacedrive.daemon 2>/dev/null || true
sd-cli daemon install  # -> Daemon installed successfully!
Defensive patterns

Strategy: try-catch

Validate before calling

# shell preflight: a loadable GUI session exists only when this prints a target
launchctl print gui/$(id -u)/com.spacedrive.daemon >/dev/null 2>&1 && echo registered || echo not-loaded

Try / catch

match install_autostart().await {
    Err(e) if e.to_string().contains("Failed to load LaunchAgent") => {
        // plist exists; finish manually with modern syntax and check lint
        let _ = std::process::Command::new("launchctl")
            .args(["bootstrap", &format!("gui/{}", uid), plist]).status();
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running `sd-cli daemon install` over SSH or another headless session where the per-user GUI domain (`gui/<uid>`) is unavailable (classic `Load failed: 5: Input/output error` or `Broken funeral`); a stale com.spacedrive.daemon job already registered in a broken state; a hand-edited plist that fails to parse.

Common situations: Remote administration over SSH without a logged-in desktop session; re-installing after a partial previous install; macOS versions where `launchctl load` is deprecated in favor of bootstrap/bootout.

Related errors


AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16). Data as JSON: /api/errors/15213a2372b4449a. Report an issue: GitHub.