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

install script pin commit `{other}` is not a valid git SHA

Error message

install script pin commit `{other}` is not a valid git SHA

What it means

Raised while resolving the install-script source: pin.commit was Some but did not pass is_valid_commit (not a plausible 40/7-hex git SHA). Because commit SHAs are the only immutable, permanently-cacheable pins, an invalid SHA cannot be trusted for cache reuse and resolution aborts rather than falling back to garbage.

Source

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

                source: ScriptSource::DevCheckout,
                commit: pin.commit.clone(),
                branch: pin.branch.clone(),
            });
        }
    }

    // 2. (Not implemented) bundled fallback.

    // 3. Network. Pin must be a real commit or a branch ref.
    //
    // Commit SHAs are immutable — permanent cache reuse is safe.
    // Branch/tag pins are moving refs: always try to refresh so "Retry install"
    // cannot keep reusing a poisoned install-main.ps1 forever (#67193).
    let (commit_or_ref, immutable) = match (&pin.commit, &pin.branch) {
        (Some(c), _) if is_valid_commit(c) => (c.clone(), true),
        (_, Some(b)) if !b.trim().is_empty() => (b.clone(), false),
        (Some(other), _) => {
            return Err(anyhow!(
                "install script pin commit `{other}` is not a valid git SHA"
            ));
        }
        _ => {
            return Err(anyhow!(
                "no install-script pin supplied — installer cannot resolve a script source"
            ));
        }
    };

    let cached = cached_path(kind, &commit_or_ref);
    match cache_plan(immutable, cached.exists()) {
        CachePlan::Reuse => {
            emit_log(&format!(
                "[bootstrap] using cached {} for {}",
                kind.filename(),
                truncate_ref(&commit_or_ref)
            ));

View on GitHub (pinned to c896c09c42)

Solutions

  1. Set the pin to a full commit SHA: `git rev-parse HEAD` and rebuild the installer with that as BUILD_PIN_COMMIT.
  2. If you meant a moving ref, pass it as the branch pin instead (BUILD_PIN_BRANCH) — branch pins are accepted and simply never cache-reused.
  3. Validate the pin before building: it must be hex (typically 40 chars).

Example fix

// before (build env)
BUILD_PIN_COMMIT=main

// after
BUILD_PIN_COMMIT=$(git rev-parse HEAD)
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_commit(s: &str) -> bool {
    let s = s.trim();
    (7..=40).contains(&s.len()) && s.chars().all(|c| c.is_ascii_hexdigit())
}

// At build time, fail fast on a bad pin:
fn main() {
    if let Some(c) = option_env!("BUILD_PIN_COMMIT") {
        assert!(is_valid_commit(c), "BUILD_PIN_COMMIT `{c}` is not a git SHA; use `git rev-parse HEAD`");
    }
}

Type guard

enum ScriptPin {
    Commit(String),   // immutable, cacheable
    Branch(String),   // moving ref, always refreshed
    None,
}

fn classify_pin(commit: Option<&str>, branch: Option<&str>) -> ScriptPin {
    match (commit, branch) {
        (Some(c), _) if is_valid_commit(c) => ScriptPin::Commit(c.to_string()),
        (_, Some(b)) if !b.trim().is_empty() => ScriptPin::Branch(b.to_string()),
        _ => ScriptPin::None,
    }
}

Prevention

When it happens

Trigger: Embedding BUILD_PIN_COMMIT with a branch name, short typo'd hash, tag, or truncated/garbage value (e.g. 'main', 'HEAD', 'abczz'); a CI variable that interpolated empty-then-whitespace; a SHA containing uppercase 'G' style placeholders from an unset env var at build time.

Common situations: Building the installer locally with BUILD_PIN_COMMIT set from a git describe/branch instead of rev-parse HEAD; CI passing a merge-ref placeholder (GITHUB_PULL_REQUEST refs) that is not a commit SHA; copy-pasting a 7-char hash that picked up a stray character.

Related errors


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