{"record":{"id":"5ca40bc5d1e02b6c","repo":"atuinsh/atuin","slug":"failed-to-read-from-input-5ca40b","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/login.rs","lineNumber":352,"sourceCode":"        let _ = meta.delete_hub_session().await;\n    }\n    crate::print_error::print_error(\n        \"Wrong encryption key\",\n        \"The encryption key on this machine does not match the data on the server. \\\n         You have been logged out.\\n\\n\\\n         To fix this, find your existing key by running `atuin key` on a machine that \\\n         already syncs successfully, then run `atuin login` again here with that key.\",\n    );\n    std::process::exit(1);\n}\n\npub(super) fn or_user_input(value: Option<String>, name: &'static str) -> String {\n    value.unwrap_or_else(|| read_user_input(name).unwrap_or_default())\n}\n\npub(super) fn read_user_password() -> String {\n    let password = prompt_password(\"Please enter password: \");\n    password.expect(\"Failed to read from input\")\n}\n\n/// Returns `None` if stdin reached end of input before a line was read.\nfn read_user_input(name: &'static str) -> Option<String> {\n    eprint!(\"Please enter {name}: \");\n    get_input().expect(\"Failed to read from input\")\n}\n\n#[cfg(test)]\nmod tests {\n    use atuin_common::encryption::paseto_v4;\n    use rstest::rstest;\n\n    #[rstest]\n    fn mnemonic_round_trip() {\n        let key = paseto_v4::Key::from([\n            3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2,\n            7, 9, 5,","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/atuinsh/atuin/blob/202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1/crates/atuin/src/command/client/account/login.rs#L334-L370","documentation":"read_user_password() backs interactive login: when `atuin login` runs without --password, it calls rpassword::prompt_password to read the account password hidden from the terminal. A failed read — no TTY, closed or empty stdin, I/O error — makes the expect panic with 'Failed to read from input'. Other flows reuse it (account delete at delete.rs:28, register).","triggerScenarios":"Running `atuin login` (or register/delete) without -p/--password where no interactive terminal exists: piped or closed stdin, cron, CI, docker without -t.","commonSituations":"Headless machine setup with `atuin login -u name` but no -p; automation assuming env-based login; containers without an allocated TTY.","solutions":["Provide the credentials via flags: atuin login --username \"$U\" --password \"$P\" --key \"$K\"","Allocate a TTY when prompting must run (docker run -it, pty wrappers)","When driving prompts from a pipe, send newline-terminated lines for every prompt (password, key) and keep stdin open"],"exampleFix":"# before — panics when stdin has no TTY\natuin login -u alice\n\n# after\natuin login -u alice -p \"$ATUIN_PASSWORD\" -k \"$ATUIN_KEY\"","handlingStrategy":"validation","validationCode":"use std::io::IsTerminal;\n\nif std::env::args().any(|a| a == \"login\")\n    && !std::env::args().any(|a| a.starts_with(\"--password\") || a == \"-p\")\n    && !std::io::stdin().is_terminal()\n{\n    eprintln!(\"atuin login needs --password when stdin is not a TTY\");\n    std::process::exit(2);\n}","typeGuard":null,"tryCatchPattern":"let password = match rpassword::prompt_password(\"Please enter password: \") {\n    Ok(pw) => pw,\n    Err(e) => {\n        eprintln!(\"cannot read password (stdin/TTY unavailable): {e}; pass --password\");\n        std::process::exit(2);\n    }\n};","preventionTips":["Provide --username/--password/--key flags for every headless login","Allocate a TTY for interactive first-run login flows","Remember delete/register flows prompt the same way; pass their flags too"],"tags":["cli","stdin","rpassword","login","panic"],"backgroundTag":"stdin-read-failure","analyzedSha":"202f6ad98ee0da165c35cdb2afbc5b13d6ab81a1","analyzedAt":"2026-08-16T19:30:24.731Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}