atuinsh/atuin · error

Failed to read from input

Error message

Failed to read from input

What it means

In `change_password.rs::run`, when `--current-password` was not supplied the command prompts interactively with `prompt_password(...)` and `.expect("Failed to read from input")`s the result. The prompt fails when stdin cannot be read — EOF/closed stdin, non-interactive environments, or terminal read errors — causing a panic instead of a friendly CLI error.

Solutions

  1. Pass the current password explicitly with `--current-password <pw>` (avoiding the prompt)
  2. Run the command in an interactive terminal
  3. If scripting, pipe the password via stdin ensuring stdin stays open until the prompt completes

Example fix

// before
let current_password = self.current_password.clone().unwrap_or_else(|| {
    prompt_password("Please enter the current password: ")
        .expect("Failed to read from input")
});
// after
let current_password = match self.current_password.clone() {
    Some(p) => p,
    None => match prompt_password("Please enter the current password: ") {
        Ok(p) => p,
        Err(e) => bail!("failed to read current password from input: {e}"),
    },
};
Defensive patterns

Strategy: validation

Validate before calling

// check interactivity before prompting
if atty::is(atty::Stream::Stdin) || std::env::var_os("ATUIN_CURRENT_PASSWORD").is_some() { /* safe to prompt */ }

Try / catch

match prompt_password("Please enter the current password: ") {
    Ok(p) => p,
    Err(e) => bail!("could not read current password (is stdin a terminal?): {e}"),
}

Prevention

When it happens

Trigger: Running `atuin account change-password` without `--current-password` in a non-interactive context: piped/closed stdin, CI jobs, nohup, or scripts that don't allocate a TTY.

Common situations: Automation and CI pipelines invoking the password change; detached shells where no terminal is attached; users piping input that ends before the prompt reads it.

Understand the failure class

Background: "no subcommand specified" and "... is required": CLI errors when a required argument is missing — this error's family across 13 libraries.

Related errors


AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19). Data as JSON: /api/errors/4f2cdb6f50b3bf75. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin/src/command/client/account/change_password.rs:30

    #[clap(long, short)]
    pub new_password: Option<String>,

    /// The two-factor authentication code for your account, if any
    #[clap(long, short)]
    pub totp_code: Option<String>,
}

impl Cmd {
    pub async fn run(&self, settings: &Settings) -> Result<()> {
        if !settings.logged_in().await? {
            bail!("You are not logged in");
        }

        let client = auth::auth_client(settings).await;

        let current_password = self.current_password.clone().unwrap_or_else(|| {
            prompt_password("Please enter the current password: ")
                .expect("Failed to read from input")
        });

        if current_password.is_empty() {
            bail!("please provide the current password");
        }

        let new_password = self.new_password.clone().unwrap_or_else(|| {
            prompt_password("Please enter the new password: ").expect("Failed to read from input")
        });

        if new_password.is_empty() {
            bail!("please provide a new password");
        }

        let mut totp_code = self.totp_code.clone();

        loop {
            let response = client

View on GitHub (pinned to 900007c480)