jdx/mise · error · eyre::Report

cannot prompt for bootstrap secret '{}' without an interacti

Error message

cannot prompt for bootstrap secret '{}' without an interactive terminal

What it means

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.

Source

Thrown at src/system/secrets.rs:339

        .next()
        .is_some_and(|first| first == '_' || first.is_ascii_alphabetic())
        && characters.all(|character| character == '_' || character.is_ascii_alphanumeric())
}

fn env_state(declaration: &SecretDeclaration) -> SecretState {
    match std::env::var_os(&declaration.env) {
        None => SecretState::Missing,
        Some(value) => match value.into_string() {
            Err(_) => SecretState::InvalidUnicode,
            Ok(value) if value.is_empty() && !declaration.allow_empty => SecretState::Empty,
            Ok(_) => SecretState::Available,
        },
    }
}

fn prompt_value(declaration: &SecretDeclaration) -> Result<String> {
    if !console::user_attended_stderr() {
        bail!(
            "cannot prompt for bootstrap secret '{}' without an interactive terminal",
            declaration.name
        );
    }
    let prompt = declaration
        .description
        .clone()
        .unwrap_or_else(|| format!("Enter bootstrap secret {}", declaration.name));
    Ok(Input::new(&prompt)
        .password(true)
        .theme(&crate::ui::theme::get_theme())
        .run()?)
}

#[cfg(test)]
mod tests {
    use super::*;

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Export the secret's environment variable before running: CACHE_TOKEN=... mise bootstrap apply
  2. Run the command from an interactive terminal so the prompt can appear
  3. Set allow_empty = true in the secret declaration if an empty value is acceptable for this environment

Example fix

# before (CI job, no tty)
mise bootstrap apply   # bails: cannot prompt for bootstrap secret 'token'
# after
env CACHE_TOKEN="$CI_CACHE_TOKEN" mise bootstrap apply
Defensive patterns

Strategy: fallback

Validate before calling

// Before any bootstrap step that needs secrets, ensure each is resolvable headless
for declaration in declarations {
    let set = std::env::var_os(&declaration.env).is_some_and(|v| !v.is_empty() || declaration.allow_empty);
    if !set && !console::user_attended_stderr() {
        bail!("secret '{}' has no value and no terminal is available to prompt", declaration.name);
    }
}

Try / catch

match result {
    Err(err) if err.to_string().contains("without an interactive terminal") => {
        // tell the operator which env vars to provide, then re-run with them set
    }
    result => result,
}

Prevention

When it happens

Trigger: 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.

Common situations: Automated provisioning in CI; first run on a fresh machine over SSH without -t; scheduled/cron runs; containers where no terminal exists.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/f8409abc4f6cfe49. Report an issue: GitHub.