NousResearch/hermes-agent

PowerShell EAP=Stop causing spurious install failures

Cluster 48352. Data as of

Nothing open on GitHub. Fix merged in #48529 on 18 Jun 2026. Check it covers your case.

The short answer

0open issues
0open PRs
4items grouped
Known?
Yes. 4 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #48529. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this unresolved. That is separate from the fix event.
Still open
Nothing open on GitHub.

These issues and PRs address a Windows install.ps1 problem where PowerShell 5.1's ErrorActionPreference=Stop incorrectly treats stderr output from native git/uv calls as fatal errors. The proposed fixes relax error handling around those native calls to prevent spurious installation failures.

Open issues0

No open issues.

Open PRs0

No open pull requests.

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #48529 fix(install): relax EAP=Stop around native git/uv calls + fail-fast on uv venv failure (#48352, salvage of #48372)

    merged to main

    files: scripts/install.ps1, tests/test_install_ps1_native_stderr_eap.py

    Show the diff
    • scripts/install.ps1
      @@ -185,6 +185,18 @@ function Write-Err {
           Write-Host "[X] $Message" -ForegroundColor Red
       }
       
      +function Invoke-NativeWithRelaxedErrorAction {
      +    param([scriptblock]$Script)
      +
      +    $prevEAP = $ErrorActionPreference
      +    $ErrorActionPreference = "Continue"
      +    try {
      +        & $Script
      +    } finally {
      +        $ErrorActionPreference = $prevEAP
      +    }
      +}
      +
       # Inspect npm output for a TLS-trust failure and, if found, print actionable
       # remediation. npm/Node surface corporate MITM proxies and missing root CAs as
       # "unable to get local issuer certificate" / "self-signed certificate in
      @@ -1306,7 +1318,7 @@ function Install-Repository {
               Write-Info "Trying SSH clone..."
               $env:GIT_SSH_COMMAND = "ssh -o BatchMode=yes -o ConnectTimeout=5"
               try {
      -            git -c windows.appendAtomically=false clone --depth 1 --branch $Branch $RepoUrlSsh $InstallDir
      +            Invoke-NativeWithRelaxedErrorAction { git -c windows.appendAtomically=false clone --depth 1 --branch $Branch $RepoUrlSsh $InstallDir }
                   if ($LASTEXITCODE -eq 0) { $cloneSuccess = $true }
               } catch { }
               $env:GIT_SSH_COMMAND = $null
      @@ -1315,7 +1327,7 @@ function Install-Repository {
                   if (Test-Path $InstallDir) { Remove-Item -Recurse -Force $InstallDir -ErrorAction SilentlyContinue }
                   Write-Info "SSH failed, trying HTTPS..."
                   try {
      -                git -c windows.appendAtomically=false clone --depth 1 --branch $Branch $RepoUrlHttps $InstallDir
      +                Invoke-NativeWithRelaxedErrorAction { git -c windows.appendAtomically=false clone --depth 1 --branch $Branch $RepoUrlHttps $InstallDir }
                       if ($LASTEXITCODE -eq 0) { $cloneSuccess = $true }
                   } catch { }
               }
      @@ -1443,8 +1455,20 @@ function Install-Venv {
               Remove-Item -Recurse -Force "venv"
           }
           
      -    # uv creates the venv and pins the Python version in one step
      -    & $UvCmd venv venv --python $PythonVersion
      +    # uv creates the venv and pins the Python version in one step.  uv emits
      +    # normal progress such as "Using CPython ..." on stderr; under Windows
      +    # PowerShell 5.1 with EAP=Stop that stderr is a NativeCommandError unless
      +    # we temporarily relax EAP and trust $LASTEXITCODE for real failures.
      +    Invoke-NativeWithRelaxedErrorAction { & $UvCmd venv venv --python $PythonVersion }
      +    # Relaxing EAP above means a *genuine* uv-venv failure (exit != 0) no longer
      +    # aborts on its own. Capture $LASTEXITCODE immediately and fail fast, so the
      +    # `venv` stage can't falsely report success (and Invoke-Stage can't emit
      +    # ok=true) when the venv was never created.
      +    $venvExitCode = $LASTEXITCODE
      +    if ($venvExitCode -ne 0) {
      +        Pop-Location
      +        throw "Failed to create virtual environment (uv venv exited with $venvExitCode)"
      +    }
       
           # Neutralize any inherited UV_PYTHON (e.g. $env:UV_PYTHON = "3.14" left in
           # the user's shell). uv honours UV_PYTHON over an existing venv for the
      @@ -1514,7 +1538,7 @@ function Install-Dependencies {
               # in the wrong directory and imports fail with ModuleNotFoundError.
               # (Mirrors the same flag in scripts/install.sh::install_deps.)
               $env:UV_PROJECT_ENVIRONMENT = "$InstallDir\venv"
      -        & $UvCmd sync --extra all --locked
      +        Invoke-NativeWithRelaxedErrorAction { & $UvCmd sync --extra all --locked }
               if ($LASTEXITCODE -eq 0) {
                   Write-Success "Main package installed (hash-verified via uv.lock)"
                   $script:InstalledTier = "hash-verified (uv.lock)"
      @@ -1589,7 +1613,7 @@ except Exception:
           if (-not $skipPipFallback) {
               foreach ($tier in $installTiers) {
               Write-Info "Trying tier: $($tier.Name) ..."
      -        & $UvCmd pip install -e $tier.Spec
      +        Invoke-NativeWithRelaxedErrorAction { & $UvCmd pip install -e $tier.Spec }
               if ($LASTEXITCODE -eq 0) {
                   Write-Success "Main package installed ($($tier.Name))"
                   $script:InstalledTier = $tier.Name
    • tests/test_install_ps1_native_stderr_eap.py
      @@ -0,0 +1,94 @@
      +"""Regression tests for #48352: Windows PowerShell 5.1 native stderr.
      +
      +PowerShell 5.1 turns stderr from native commands into ``NativeCommandError``
      +records when ``$ErrorActionPreference = "Stop"``.  ``scripts/install.ps1`` has a
      +few git/uv calls where stderr can be normal progress output, so those calls must
      +run with EAP temporarily relaxed and then inspect ``$LASTEXITCODE``.
      +"""
      +
      +from __future__ import annotations
      +
      +import re
      +from pathlib import Path
      +
      +REPO_ROOT = Path(__file__).resolve().parent.parent
      +INSTALL_PS1 = REPO_ROOT / "scripts" / "install.ps1"
      +
      +
      +def _install_ps1() -> str:
      +    return INSTALL_PS1.read_text(encoding="utf-8")
      +
      +
      +def _assert_relaxed_call(text: str, command_pattern: str) -> None:
      +    helper_block_pattern = (
      +        r"Invoke-NativeWithRelaxedErrorAction\s*\{[^}]*"
      +        + command_pattern
      +        + r"[^}]*\}"
      +    )
      +    inline_pattern = (
      +        r"\$ErrorActionPreference\s*=\s*\"Continue\"[\s\S]{0,900}?"
      +        + command_pattern
      +    )
      +    assert re.search(helper_block_pattern, text) or re.search(inline_pattern, text), (
      +        f"install.ps1 must relax ErrorActionPreference around {command_pattern}"
      +    )
      +
      +
      +def test_repository_stage_relieves_eap_for_ssh_and_https_git_clone() -> None:
      +    text = _install_ps1()
      +    assert "function Invoke-NativeWithRelaxedErrorAction" in text
      +    _assert_relaxed_call(
      +        text,
      +        r"git -c windows\.appendAtomically=false clone --depth 1 --branch \$Branch \$RepoUrlSsh \$InstallDir",
      +    )
      +    _assert_relaxed_call(
      +        text,
      +        r"git -c windows\.appendAtomically=false clone --depth 1 --branch \$Branch \$RepoUrlHttps \$InstallDir",
      +    )
      +
      +
      +def test_uv_venv_and_dependency_installs_relax_eap() -> None:
      +    text = _install_ps1()
      +    _assert_relaxed_call(text, r"& \$UvCmd venv venv --python \$PythonVersion")
      +    _assert_relaxed_call(text, r"& \$UvCmd sync --extra all --locked")
      +    _assert_relaxed_call(text, r"& \$UvCmd pip install -e \$tier\.Spec")
      +
      +
      +def test_uv_venv_failure_is_not_swallowed_after_eap_relax() -> None:
      +    """Relaxing EAP must not let a genuine `uv venv` failure pass as success.
      +
      +    Once EAP is relaxed, a real non-zero `uv venv` exit no longer aborts on its
      +    own, so install.ps1 must capture $LASTEXITCODE right after the call and fail
      +    fast — otherwise the `venv` stage falsely reports success (Invoke-Stage emits
      +    ok=true) when no venv was created. Regression guard for the gap caught while
      +    reviewing #48372 (the explicit check originally proposed in #48463).
      +    """
      +    text = _install_ps1()
      +    # The uv-venv invocation, then an exit-code capture, then a throw — all
      +    # within a small window after the relaxed call.
      +    guard = re.search(
      +        r"& \$UvCmd venv venv --python \$PythonVersion[\s\S]{0,400}?"
      +        r"\$LASTEXITCODE[\s\S]{0,200}?"
      +        r"-ne 0[\s\S]{0,200}?throw",
      +        text,
      +    )
      +    assert guard is not None, (
      +        "install.ps1 must capture uv venv's exit code and throw on failure after "
      +        "relaxing ErrorActionPreference, so a genuine venv-creation failure isn't "
      +        "reported as a successful stage"
      +    )
      +
      +
      +def test_native_eap_helper_always_restores_previous_preference() -> None:
      +    text = _install_ps1()
      +    m = re.search(
      +        r"function Invoke-NativeWithRelaxedErrorAction \{(?P<body>[\s\S]*?)^\}",
      +        text,
      +        re.MULTILINE,
      +    )
      +    assert m is not None, "expected a shared helper for NativeCommandError-safe calls"
      +    body = m.group("body")
      +    assert "$prevEAP = $ErrorActionPreference" in body
      +    assert '$ErrorActionPreference = "Continue"' in body
      +    assert "finally" in body
      +    assert "$ErrorActionPreference = $prevEAP" in body

2 PRs closed without merging

From the close comments: duplicate 1 · merged via another change 1

  • #48372 fix(install): relax native stderr handling in install.ps1 (#48352) · merged via another change → #48529, #48352
  • #48463 fix(install): relax EAP=Stop around git/uv native calls in install.ps1 (#48352) · duplicate → #48529, #48372
Closed issues · 1
  • Closed#48352install.ps1 (Windows): PowerShell 5.1 NativeCommandError wrapping of git/uv stderr causes spurious install failures
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.50: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Merged PRs
#48529
Closed issues
1
Attempts
2 PRs closed without merging
Fix link checked
18 Jun 2026

For your agent

The same facts, typed.