{"record":{"id":"f8409abc4f6cfe49","repo":"jdx/mise","slug":"cannot-prompt-for-bootstrap-secret-without-an","errorCode":null,"errorMessage":"cannot prompt for bootstrap secret '{}' without an interactive terminal","messagePattern":"cannot prompt for bootstrap secret '(.+?)' without an interactive terminal","errorType":"exception","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/secrets.rs","lineNumber":339,"sourceCode":"        .next()\n        .is_some_and(|first| first == '_' || first.is_ascii_alphabetic())\n        && characters.all(|character| character == '_' || character.is_ascii_alphanumeric())\n}\n\nfn env_state(declaration: &SecretDeclaration) -> SecretState {\n    match std::env::var_os(&declaration.env) {\n        None => SecretState::Missing,\n        Some(value) => match value.into_string() {\n            Err(_) => SecretState::InvalidUnicode,\n            Ok(value) if value.is_empty() && !declaration.allow_empty => SecretState::Empty,\n            Ok(_) => SecretState::Available,\n        },\n    }\n}\n\nfn prompt_value(declaration: &SecretDeclaration) -> Result<String> {\n    if !console::user_attended_stderr() {\n        bail!(\n            \"cannot prompt for bootstrap secret '{}' without an interactive terminal\",\n            declaration.name\n        );\n    }\n    let prompt = declaration\n        .description\n        .clone()\n        .unwrap_or_else(|| format!(\"Enter bootstrap secret {}\", declaration.name));\n    Ok(Input::new(&prompt)\n        .password(true)\n        .theme(&crate::ui::theme::get_theme())\n        .run()?)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/secrets.rs#L321-L357","documentation":"When a declared secret's environment variable is missing or empty, mise falls back to prompting for the value on stderr. prompt_value first checks console::user_attended_stderr(); with no interactive terminal it refuses to prompt rather than hang, because the password Input read cannot work headless.","triggerScenarios":"Running any bootstrap step that materializes secrets when stderr is not a TTY or the process is not user-attended: CI pipelines, cron, `ssh host mise ...` (non-interactive), piped/redirected stderr, or running under a service manager.","commonSituations":"Automated provisioning in CI; first run on a fresh machine over SSH without -t; scheduled/cron runs; containers where no terminal exists.","solutions":["Export the secret's environment variable before running: CACHE_TOKEN=... mise bootstrap apply","Run the command from an interactive terminal so the prompt can appear","Set allow_empty = true in the secret declaration if an empty value is acceptable for this environment"],"exampleFix":"# before (CI job, no tty)\nmise bootstrap apply   # bails: cannot prompt for bootstrap secret 'token'\n# after\nenv CACHE_TOKEN=\"$CI_CACHE_TOKEN\" mise bootstrap apply","handlingStrategy":"fallback","validationCode":"// Before any bootstrap step that needs secrets, ensure each is resolvable headless\nfor declaration in declarations {\n    let set = std::env::var_os(&declaration.env).is_some_and(|v| !v.is_empty() || declaration.allow_empty);\n    if !set && !console::user_attended_stderr() {\n        bail!(\"secret '{}' has no value and no terminal is available to prompt\", declaration.name);\n    }\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(err) if err.to_string().contains(\"without an interactive terminal\") => {\n        // tell the operator which env vars to provide, then re-run with them set\n    }\n    result => result,\n}","preventionTips":["Pre-set all declared secret env vars in CI/cron/ssh environments","Use `ssh -t` when a one-off interactive bootstrap must prompt","Mark optional secrets allow_empty = true so headless runs do not block on them"],"tags":["bootstrap","secrets","interactive","tty","ci"],"backgroundTag":"non-interactive-prompt-unavailable","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}