NousResearch/hermes-agent · error · Error

First-run remote setup completed without a saved remote back

Error message

First-run remote setup completed without a saved remote backend.

What it means

Thrown during first-run backend startup in the Hermes desktop app. When waitForDecision(backend) returns 'remote-applied', the code re-resolves the saved remote backend; if resolveRemote() returns nothing, the wizard claimed the remote was applied but nothing was persisted. This is an internal invariant failure, not a user-input error.

Source

Thrown at apps/desktop/electron/primary-backend-startup.ts:54

}: PrimaryBackendStartupOptions<Backend, RuntimeBackend, Remote, Connection>): Promise<
  PrimaryBackendStartupResult<RuntimeBackend, Connection>
> {
  const savedRemote = await resolveRemote()

  if (savedRemote) {
    return { kind: 'remote', connection: await connectRemote(savedRemote) }
  }

  await waitForLocalStart()

  const backend = await prepareLocalBackend()
  const decision = await waitForDecision(backend)

  if (decision === 'remote-applied') {
    const appliedRemote = await resolveRemote()

    if (!appliedRemote) {
      throw new Error('First-run remote setup completed without a saved remote backend.')
    }

    return { kind: 'remote', connection: await connectRemote(appliedRemote) }
  }

  if (decision === 'reset') {
    throw new FirstRunSetupResetError()
  }

  return { kind: 'local', backend: await ensureLocalRuntime(backend) }
}

View on GitHub (pinned to c896c09c42)

Solutions

  1. Compare the wizard's apply-step write (file, key, schema) against exactly what resolveRemote() reads — a mismatch is the usual cause.
  2. Re-run first-run setup (reset the first-run marker) and walk the remote wizard again; if it persists this time, the first attempt hit a transient write failure.
  3. Check filesystem permissions and disk space where the remote config is stored so writes cannot fail silently.
  4. If reproducible, instrument the 'remote-applied' branch to log the result of the apply write immediately after it returns.

Example fix

// before
if (decision === 'remote-applied') {
  const appliedRemote = await resolveRemote()
  if (!appliedRemote) throw new Error('First-run remote setup completed without a saved remote backend.')
  return { kind: 'remote', connection: await connectRemote(appliedRemote) }
}

// after (fall back to the already-prepared local backend instead of crashing first run)
if (decision === 'remote-applied') {
  const appliedRemote = await resolveRemote()
  if (!appliedRemote) {
    log.error('remote-applied but resolveRemote() empty; remote config never persisted')
    return { kind: 'local', backend: await ensureLocalRuntime(backend) }
  }
  return { kind: 'remote', connection: await connectRemote(appliedRemote) }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (decision === 'remote-applied') {
  const appliedRemote = await resolveRemote()
  if (!appliedRemote) {
    // fall back to the already-prepared local backend rather than crashing first run
    return { kind: 'local', backend: await ensureLocalRuntime(backend) }
  }
}

Try / catch

try {
  return await startPrimaryBackend()
} catch (e) {
  if (e instanceof Error && e.message === 'First-run remote setup completed without a saved remote backend.') {
    // the remote config never landed: re-run the first-run wizard
    return await startFirstRunWizard()
  }
  if (e instanceof FirstRunSetupResetError) return null // user reset: expected path
  throw e
}

Prevention

When it happens

Trigger: decision === 'remote-applied' but a subsequent resolveRemote() yields null/undefined — the wizard's apply step failed to persist, wrote to a different location/key than resolveRemote() reads, or a concurrent reset/clear removed the config between apply and resolve.

Common situations: Config write race during first run (app quit or another window cleared config mid-wizard); a version mismatch where the wizard persists the remote under a key or schema the resolver does not read; permissions failure writing the config file so the apply write failed silently.

Related errors


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