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.

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.

Appendix: 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)