NousResearch/hermes-agent · warning · Error

Hermes backend start was superseded by a newer connection at

Error message

Hermes backend start was superseded by a newer connection attempt.

What it means

Thrown when a freshly spawned Hermes backend child process loses a race: backendConnectionState.attachProcess(connectionAttempt, hermesProcess) returned falsy, meaning a newer connection attempt superseded this one while the spawn was in flight. The child is stopped (stopBackendChild) and the older attempt aborts rather than leaking a process attached to a dead attempt. This is a deliberate last-writer-wins guard, so it indicates rapid sequential reconnects, not a broken backend.

Source

Thrown at apps/desktop/electron/main.ts:8520

          HERMES_DESKTOP: '1',
          // Our PID so the backend's parent-death watchdog self-exits if we die
          // uncleanly (crash / SIGKILL / update handoff) instead of leaking a
          // serving backend + its MCP child subtree. See web_server.py
          // _start_parent_death_watchdog.
          HERMES_PARENT_PID: String(process.pid),
          HERMES_WEB_DIST: webDist,
          ...(readyFile ? { HERMES_DESKTOP_READY_FILE: readyFile } : {})
        },
        shell: backend.shell,
        stdio: ['ignore', 'pipe', 'pipe']
      })
    )

    const processOwner = backendConnectionState.attachProcess(connectionAttempt, hermesProcess)

    if (!processOwner) {
      stopBackendChild(hermesProcess)
      throw new Error('Hermes backend start was superseded by a newer connection attempt.')
    }

    hermesProcess.stdout.on('data', rememberLog)
    hermesProcess.stderr.on('data', rememberLog)
    let backendReady = false
    let rejectBackendStart = null

    const backendStartFailed = new Promise((_resolve, reject) => {
      rejectBackendStart = reject
    })

    hermesProcess.once('error', error => {
      if (!backendConnectionState.clearForCurrentProcess(processOwner)) {
        rememberLog(`Ignoring stale Hermes backend error: ${error.message}`)
        rejectBackendStart?.(new Error('Hermes backend start was superseded by a newer connection attempt.'))

        return
      }

View on GitHub (pinned to c896c09c42)

Solutions

  1. Let the in-flight connection attempt finish (or explicitly disconnect) before starting another — avoid rapid reconnect clicks
  2. If it appears during normal single-click use, check for a renderer-side retry loop issuing duplicate boot requests and debounce it
  3. Verify the process is actually cleaned up (no orphan 'hermes serve' child) after this error, then connect once cleanly
  4. Treat this error as retryable in UI: surface 'connection attempt was replaced' rather than a hard failure

Example fix

// before (renderer)
onClick={() => void window.hermes.bootBackend(profile)} // fires on every click

// after
const booting = useRef(false)
onClick={() => { if (booting.current) return; booting.current = true; void window.hermes.bootBackend(profile).finally(() => { booting.current = false }) }}
Defensive patterns

Strategy: try-catch

Validate before calling

// Serialize connection attempts in the renderer
let bootInFlight: Promise<BootResult> | null = null
function boot(profile: string) {
  bootInFlight ??= ipc.invoke('hermes:boot', profile).finally(() => { bootInFlight = null })
  return bootInFlight
}

Type guard

function isSupersededAttempt(e: unknown): boolean {
  return e instanceof Error && e.message === 'Hermes backend start was superseded by a newer connection attempt.'
}

Try / catch

try { await bootBackend(profile) } catch (e) { if (isSupersededAttempt(e)) { /* benign race: a newer attempt owns the boot; do nothing */ return } throw e }

Prevention

When it happens

Trigger: User (or renderer logic) triggers connect/disconnect/connect quickly; a failed connection attempt auto-retries while the user manually reconnects; two profiles or windows race to boot backends in the same main process. attachProcess is called after spawn resolves, by which time connectionAttempt is no longer the current attempt.

Common situations: Clicking 'reconnect' repeatedly in the desktop UI during a slow backend boot; an auto-retry loop stacked on top of user-initiated connects; dev hot-restarts of the renderer re-issuing the boot IPC.

Related errors


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