NousResearch/hermes-agent · error · anyhow::Error

write bootstrap marker failed

Error message

write bootstrap marker failed: {err:#}

What it means

Raised when write_bootstrap_complete_marker() fails to persist the completion marker JSON under the install root (create the marker directory, serialize the JSON, or write the file failed). The marker records schemaVersion, pinned commit/branch, and completion time, and doubles as the cross-process update lock shared with `hermes update` (hermes_cli/update_lock.py). Because the UI relies on the marker to leave the progress state, the installer treats an unwritable marker as a hard failure of an otherwise-finished install.

Solutions

  1. Free disk space and verify write access to the marker path shown in the error's install root (create the directory by hand as a test).
  2. Delete the stale marker file so the installer can recreate it with fresh permissions.
  3. Re-run the installer elevated (Windows) or fix ownership of HERMES_HOME (chmod/chown on macOS/Linux).
  4. Temporarily disable/reconfigure antivirus real-time scanning for HERMES_HOME and retry.
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
use std::fs;

fn marker_writable(install_root: &Path) -> std::io::Result<()> {
    let marker = crate::paths::likely_bootstrap_marker(install_root);
    if let Some(parent) = marker.parent() {
        fs::create_dir_all(parent)?;
        let probe = parent.join(".write-probe");
        fs::write(&probe, b"x")?;
        let _ = fs::remove_file(&probe);
    }
    Ok(())
}

// Run before install: bail early with a clear message if the marker can't be written.
if let Err(e) = marker_writable(&install_root) {
    eprintln!("HERMES_HOME not writable: {e}");
}

Try / catch

match write_bootstrap_complete_marker(&install_root, &pin) {
    Ok(m) => m,
    Err(err) => {
        // Install itself succeeded; surface as recoverable, point user at permissions/disk.
        emit_event(&app, BootstrapEvent::Failed { stage: None,
            error: format!("install finished but the completion marker could not be written: {err:#}. Check disk space and permissions on the install root.") });
        return Err(anyhow!("write bootstrap marker failed: {err:#}"));
    }
}

Prevention

When it happens

Trigger: Calling the bootstrap finish path when HERMES_HOME or the install root is on a read-only/full disk, when the marker's parent directory cannot be created (permission denied), when serde_json serialization of the marker value fails (practically never), or when antivirus/another process holds the marker file open with an exclusive lock on Windows.

Common situations: Disk full on the drive holding HERMES_HOME; running the installer without write permission to the user profile dir; a stale marker file with restrictive ACLs from a previous run under a different account; OneDrive/antivirus locking .json files in the home directory.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/8f9f15ed2dc5a71b. Report an issue: GitHub.

Appendix: source

Thrown at apps/bootstrap-installer/src-tauri/src/bootstrap.rs:801

        .hermes_home
        .clone()
        .unwrap_or_else(|| crate::paths::hermes_home().to_string_lossy().into_owned());
    let install_root = PathBuf::from(&hermes_home).join("hermes-agent");

    // Marker publish is terminal for this run: a write failure must emit Failed
    // so the UI leaves the progress state (it does not poll get_bootstrap_status).
    let marker = match write_bootstrap_complete_marker(&install_root, &pin) {
        Ok(marker) => marker,
        Err(err) => {
            let msg = format!("write bootstrap marker failed: {err:#}");
            emit_event(
                &app,
                BootstrapEvent::Failed {
                    stage: None,
                    error: msg.clone(),
                },
            );
            return Err(anyhow!(msg));
        }
    };

    // Copy ourselves to HERMES_HOME/hermes-setup.exe so the desktop app can
    // re-invoke us with `--update` and shortcuts have a stable target. This is
    // a one-shot install concern; an `--update` re-invocation no-ops because
    // we're already running from that path. Best-effort — a failure here must
    // not fail an otherwise-successful install.
    if let Err(err) = crate::paths::copy_self_to_hermes_home() {
        tracing::warn!(?err, "failed to copy installer into HERMES_HOME (non-fatal)");
        emit_log(&format!(
            "[bootstrap] warning: could not stage updater binary: {err}"
        ));
    }

    emit_event(
        &app,
        BootstrapEvent::Complete {

View on GitHub (pinned to c896c09c42)