{"record":{"id":"1300d2d834024886","repo":"spacedriveapp/spacedrive","slug":"aborted-by-user","errorCode":null,"errorMessage":"Aborted by user","messagePattern":"Aborted by user","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"info","filePath":"apps/cli/src/util/confirm.rs","lineNumber":31,"sourceCode":"\t\t|| std::env::var(\"SD_CLI_YES\")\n\t\t\t.map(|v| v == \"1\" || v.eq_ignore_ascii_case(\"true\"))\n\t\t\t.unwrap_or(false)\n\t{\n\t\treturn Ok(());\n\t}\n\n\tuse std::io::{self, Write};\n\tlet mut stderr = io::stderr();\n\twriteln!(stderr, \"{} [y/N]: \", prompt)?;\n\tstderr.flush()?;\n\n\tlet mut input = String::new();\n\tio::stdin().read_line(&mut input)?;\n\tlet resp = input.trim().to_ascii_lowercase();\n\tif resp == \"y\" || resp == \"yes\" {\n\t\tOk(())\n\t} else {\n\t\tanyhow::bail!(\"Aborted by user\")\n\t}\n}\n\n/// Prompt the user for a multiple-choice selection.\n/// Returns the 0-based index of the selected choice.\npub fn prompt_for_choice(request: ConfirmationRequest) -> Result<usize> {\n\tuse std::io::{self, Write};\n\n\tprintln!(\"{}\", request.message);\n\tfor (i, choice) in request.choices.iter().enumerate() {\n\t\tprintln!(\"  [{}]: {}\", i + 1, choice);\n\t}\n\n\tloop {\n\t\tprint!(\"Please select an option (1-{}): \", request.choices.len());\n\t\tio::stdout().flush()?;\n\n\t\tlet mut input = String::new();","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/apps/cli/src/util/confirm.rs#L13-L49","documentation":"confirm() prints a '[y/N]' prompt and accepts only 'y' or 'yes' (case-insensitive) as consent; anything else, including empty input and EOF, bails with 'Aborted by user'. This is deliberate control flow for destructive commands ('sd stop --reset', library deletion), not a malfunction.","triggerScenarios":"Answering 'n', pressing Enter on the default No, piping a script into sd so stdin is at EOF, or answering 'Y ' with unexpected characters.","commonSituations":"Automating destructive commands without providing consent; users changing their mind at the confirmation.","solutions":["Re-run the command and answer 'y' if you actually want the action","In scripts, pre-feed consent only when intended: printf 'y\\n' | sd stop --reset","Treat the non-zero exit as cancellation and skip retry logic"],"exampleFix":"# before: script hangs or aborts at prompt\nsd stop --reset\n\n# after: explicit consent for automation\nprintf 'y\\n' | sd stop --reset","handlingStrategy":"try-catch","validationCode":"#!/usr/bin/env bash\n# Non-interactive: decide before prompting\nif [ \"$ASSUME_YES\" = 1 ]; then\n  printf 'y\\n' | sd stop --reset\nelse\n  sd stop --reset  # interactive; expect possible abort\nfi","typeGuard":null,"tryCatchPattern":"match confirm(prompt) {\n    Ok(()) => { /* proceed with destructive action */ }\n    Err(e) if e.to_string() == \"Aborted by user\" => {\n        println!(\"Cancelled; no changes were made.\");\n        std::process::exit(130); // 128+SIGINT convention for user interrupt\n    }\n    Err(e) => return Err(e), // real IO failure, e.g. broken stdin\n}","preventionTips":["Treat 'Aborted by user' as a success-path cancellation with a distinct exit code, not an error","Never feed blind 'yes' into prompts in scripts; gate consent behind an explicit flag","When stdin is not a TTY, skip prompting and require a --yes/--force flag instead"],"tags":["cli","confirmation","user-input","control-flow"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}