atuinsh/atuin · error
{reason}. Enable `daemon.autostart = true` or restart the da
Error message
{reason}. Enable `daemon.autostart = true` or restart the daemon manually What it means
ready_client probes the daemon for readiness and returns a ready HistoryClient only if version/protocol match. When the probe reports NeedsRestart but autostart is disabled, the client cannot recover on its own and bails with the same remediation hint. It is the top-level guard used before issuing daemon RPCs.
Source
Thrown at crates/atuin/src/command/client/daemon.rs:442
let message = daemon_mismatch_message(version, protocol);
if settings.daemon.autostart {
bail!("{message}");
}
bail!("{message}. Enable `daemon.autostart = true` or restart the daemon manually");
}
/// Acquire a [`HistoryClient`] connected to a daemon we expect to understand us, probing over the
/// wire-stable Status RPC first and restarting the daemon if it is absent or version/protocol
/// skewed.
///
/// TODO(markovejnovic): This is egregious slop, but not worse than the original solution. I want to
/// remove this in a future PR: <https://github.com/atuinsh/atuin/pull/4002>
pub async fn ready_client(settings: &Settings) -> Result<HistoryClient> {
match probe(settings).await {
Probe::Ready(client) => return Ok(client),
Probe::NeedsRestart(reason) if !settings.daemon.autostart => {
bail!("{reason}. Enable `daemon.autostart = true` or restart the daemon manually");
}
Probe::Unreachable(err) if is_legacy_daemon_error(&err) => {
return Err(err.wrap_err(LEGACY_DAEMON_RESTART_MESSAGE));
}
Probe::Unreachable(err) if !settings.daemon.autostart => return Err(err),
Probe::Unreachable(err) if !should_retry_after_error(&err) => return Err(err),
Probe::NeedsRestart(_) | Probe::Unreachable(_) => {}
}
restart_daemon(settings).await
}
/// Send a request to the daemon, first ensuring (via [`ready_client`]) that it is running and
/// speaks our version.
async fn try_with_restart<C, F, R>(settings: &Settings, send_request: F, context: C) -> Result<R>
where
F: AsyncFn(&mut HistoryClient, C) -> Result<R> + Sync,
R: atuin_daemon::grpc::VersionedReply,View on GitHub (pinned to c0c717ab04)
Solutions
- Restart the daemon manually so version/protocol match the CLI
- Enable daemon.autostart = true in the Atuin config so the client restarts skewed daemons automatically
- Ensure only one atuin installation provides the daemon
Example fix
// before (config.toml) [daemon] autostart = false // after [daemon] autostart = true
Defensive patterns
Strategy: try-catch
Validate before calling
let cfg: toml::Value = toml::from_str(&std::fs::read_to_string("~/.config/atuin/config.toml")?)?;
if !cfg["daemon"]["autostart"].as_bool().unwrap_or(false) {
eprintln!("autostart disabled: ensure the running daemon matches this CLI version");
} Try / catch
match ready_client(&settings).await {
Err(e) if e.to_string().contains("Enable `daemon.autostart = true`") => {
// restart daemon and retry
}
other => other?,
} Prevention
- Enable autostart to avoid manual restarts
- Probe daemon status (`atuin daemon status`) after upgrades
- Pin CLI and daemon to the same version
When it happens
Trigger: probe() returns Probe::NeedsRestart(reason) (version or protocol skew) while settings.daemon.autostart is false; called from try_with_restart during any daemon-backed command.
Common situations: Same as error 80: stale daemon after an upgrade, mixed installations, autostart disabled in config.
Related errors
- {message}. Enable `daemon.autostart = true` or restart the d
- {message}
- daemon sent a lag notice as a history event
- daemon sent an unspecified history tail event
- payload length fits in u32
AI-assisted analysis of atuinsh/atuin@c0c717ab04 (2026-09-12).
Data as JSON: /api/errors/d935830d81821d51.
Report an issue: GitHub.