{"record":{"id":"4f2cdb6f50b3bf75","repo":"atuinsh/atuin","slug":"failed-to-read-from-input","errorCode":null,"errorMessage":"Failed to read from input","messagePattern":"Failed to read from input","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/atuin/src/command/client/account/change_password.rs","lineNumber":33,"sourceCode":"    #[clap(long, short)]\n    pub new_password: Option<String>,\n\n    /// The two-factor authentication code for your account, if any\n    #[clap(long, short)]\n    pub totp_code: Option<String>,\n}\n\nimpl Cmd {\n    pub async fn run(&self, settings: &Settings) -> Result<()> {\n        if !settings.logged_in().await? {\n            bail!(\"You are not logged in\");\n        }\n\n        let client = auth::auth_client(settings).await;\n\n        let current_password = self.current_password.clone().unwrap_or_else(|| {\n            prompt_password(\"Please enter the current password: \")\n                .expect(\"Failed to read from input\")\n        });\n\n        if current_password.is_empty() {\n            bail!(\"please provide the current password\");\n        }\n\n        let new_password = self.new_password.clone().unwrap_or_else(|| {\n            prompt_password(\"Please enter the new password: \").expect(\"Failed to read from input\")\n        });\n\n        if new_password.is_empty() {\n            bail!(\"please provide a new password\");\n        }\n\n        let mut totp_code = self.totp_code.clone();\n\n        loop {\n            let response = client","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/atuinsh/atuin/blob/202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1/crates/atuin/src/command/client/account/change_password.rs#L15-L51","documentation":"When `atuin account change-password` runs without --current-password, it prompts via rpassword::prompt_password, which reads a hidden password from the terminal. If the read fails — stdin closed (EOF, /dev/null), no controlling TTY, or an I/O error — the expect panics with 'Failed to read from input'.","triggerScenarios":"Running `atuin account change-password` without --current-password in a non-interactive context: stdin redirected from /dev/null or an exhausted pipe, or no TTY attached (cron, CI, docker run/exec without -t).","commonSituations":"Automation scripts that forgot the flag; CI pipelines; docker exec into containers without a TTY; piping empty input into atuin.","solutions":["Pass the values as flags: atuin account change-password --current-password \"$OLD\" --new-password \"$NEW\"","Run the command in an interactive terminal (docker run -it / docker exec -it)","If driving the prompt from a pipe, supply a newline-terminated line and keep stdin open until the command exits"],"exampleFix":"# before — panics: no TTY, stdin empty\natuin account change-password < /dev/null\n\n# after — headless flags\natuin account change-password --current-password \"$OLD\" --new-password \"$NEW\"","handlingStrategy":"validation","validationCode":"use std::io::IsTerminal;\n\nlet has_flag = std::env::args().any(|a| a.starts_with(\"--current-password\"));\nif !has_flag && !std::io::stdin().is_terminal() {\n    eprintln!(\"change-password needs --current-password when stdin is not a TTY\");\n    std::process::exit(2);\n}","typeGuard":null,"tryCatchPattern":"let current_password = match rpassword::prompt_password(\"Please enter the current password: \") {\n    Ok(pw) => pw,\n    Err(e) => {\n        eprintln!(\"cannot read password (stdin/TTY unavailable): {e}\");\n        std::process::exit(2);\n    }\n};","preventionTips":["In scripts and CI, always pass credentials via flags instead of relying on prompts","Allocate a TTY (docker -it, pty wrapper) when interactive prompts must run","Fail fast on non-TTY stdin before invoking interactive subcommands"],"tags":["cli","stdin","rpassword","interactive-prompt","panic"],"backgroundTag":"stdin-read-failure","analyzedSha":"202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1","analyzedAt":"2026-08-16T19:30:24.731Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}