atuinsh/atuin · error
{message}. Enable `daemon.autostart = true` or restart the d
Error message
{message}. Enable `daemon.autostart = true` or restart the daemon manually What it means
When the running daemon's version or wire protocol does not match what the CLI expects, ensure_reply_compatible builds a mismatch message and bails. If daemon autostart is disabled, the CLI cannot restart the daemon itself, so it appends advice to either enable autostart or restart manually. This protects the client from talking to a daemon it cannot interoperate with.
Source
Thrown at crates/atuin/src/command/client/daemon.rs:429
Ok(())
}
async fn restart_daemon(settings: &Settings) -> Result<HistoryClient> {
ensure_daemon_running(settings).await?;
connect_client(settings).await
}
fn ensure_reply_compatible(settings: &Settings, version: &str, protocol: u32) -> Result<()> {
if daemon_matches_expected(version, protocol) {
return Ok(());
}
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),View on GitHub (pinned to c0c717ab04)
Solutions
- Restart the atuin daemon manually (atuin daemon stop && atuin daemon start) so it matches the CLI version
- Set daemon.autostart = true in ~/.config/atuin/config.toml so the CLI can restart a mismatched daemon automatically
- Kill the stale daemon process and rerun the command
Example fix
// before (config.toml) [daemon] autostart = false // after [daemon] autostart = true
Defensive patterns
Strategy: try-catch
Validate before calling
// check config before running daemon-backed commands
let cfg: toml::Value = toml::from_str(&std::fs::read_to_string("~/.config/atuin/config.toml")?)?;
let autostart = cfg.get("daemon").and_then(|d| d.get("autostart")).and_then(|v| v.as_bool()).unwrap_or(false);
if !autostart { eprintln!("daemon.autostart is disabled; restart the daemon manually after upgrades"); } Try / catch
match cmd.await {
Err(e) if e.to_string().contains("Enable `daemon.autostart = true`") => {
// restart daemon manually, then retry once
}
other => other?,
} Prevention
- Keep daemon.autostart = true so version skew self-heals
- Restart the daemon after every atuin upgrade
- Use one installation method for the CLI and daemon
When it happens
Trigger: The CLI connects to a daemon whose reported version or protocol differs from the CLI's own, and settings.daemon.autostart is false, so try_with_restart cannot recover by restarting the daemon.
Common situations: Upgrading the atuin binary while an old daemon process is still running; daemons started from a different install (distro package vs cargo install); autostart explicitly disabled in config.
Related errors
- {reason}. Enable `daemon.autostart = true` or restart the da
- {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/f12dd1aed130f1e6.
Report an issue: GitHub.