zeroclaw-labs/zeroclaw · error · anyhow::Error
cli-secret-needs-tty
cli-secret-needs-tty
Error message
Secret input requires a terminal on stdin and stderr.
What it means
secret_prompt reads hidden input via cli_input::SecretInput, which needs a real terminal on both stdin (to read the secret) and stderr (to render the prompt and mask feedback). If either stream is not a TTY, the prompt cannot work safely and the call aborts before reading anything (i18n key 'cli-secret-needs-tty', stable code of the same name).
Source
Thrown at src/main.rs:151
{
zeroclaw_runtime::i18n::get_required_cli_string_with_args(key, args)
}
#[cfg(not(feature = "agent-runtime"))]
{
fallback.to_string() // i18n-exempt: English fallback when Fluent (agent-runtime) is disabled
}
}
/// Interactive secret prompt with pre-submit feedback.
///
/// The value stays hidden, but the prompt shows a bounded mask once the input
/// buffer becomes non-empty.
#[cfg(feature = "agent-runtime")]
fn secret_prompt(prompt_text: &str, allow_empty: bool) -> Result<String> {
use std::io::IsTerminal;
if !std::io::stdin().is_terminal() || !std::io::stderr().is_terminal() {
bail!(ta(
"cli-secret-needs-tty",
&[],
"Secret input requires a terminal on stdin and stderr."
));
}
let value = cli_input::SecretInput::new()
.with_prompt(prompt_text)
.interact()?;
if allow_empty || !value.trim().is_empty() {
Ok(value)
} else {
bail!(ta("cli-secret-empty", &[], "Value cannot be empty."))
}
}
#[cfg(feature = "agent-runtime")]
fn qta(key: &str, args: &[(&str, &str)]) -> String {View on GitHub (pinned to 88bb9c8533)
Solutions
- Run the command from an interactive terminal so both stdin and stderr are TTYs.
- In containers use `docker exec -it <container> zeroclaw ...`; over SSH drop one-shot mode so a TTY is allocated.
- For automation, provision the secret non-interactively (config file or the documented env-var route) instead of relying on the prompt.
- If you must automate the prompt, drive it through a pty wrapper such as `expect` or `script`.
Example fix
# before: no tty, prompt aborts docker exec zeroclaw zeroclaw onboard # Secret input requires a terminal... # after: allocate a tty docker exec -it zeroclaw zeroclaw onboard
Defensive patterns
Strategy: fallback
Validate before calling
use std::io::IsTerminal;
fn can_prompt_secret() -> bool {
std::io::stdin().is_terminal() && std::io::stderr().is_terminal()
}
// in automation: if !can_prompt_secret(), provision the secret via the
// documented non-interactive route (config/env) instead of invoking the prompt Try / catch
match run_onboarding().await {
Err(e) if e.to_string().contains("requires a terminal") => {
// no TTY: switch to the non-interactive provisioning path or re-run
// inside `docker exec -it` / an interactive ssh session
}
other => other,
} Prevention
- Never pipe answers into zeroclaw commands that prompt for secrets; detect TTY first and branch.
- Use `docker exec -it` for container onboarding and interactive ssh (no one-shot command) remotely.
- Pre-provision secrets via config or env in CI so interactive prompts are never reached.
When it happens
Trigger: Invoking any zeroclaw flow that prompts for a secret (e.g. provider API key onboarding) with stdin or stderr redirected: piping answers in (`echo y | zeroclaw ...`), running under CI, daemons, plain `docker exec` without -t, or scripts with stdin from a file.
Common situations: Automating first-run setup in containers or CI where no terminal exists; SSH one-shot commands (`ssh host zeroclaw ...` allocates no TTY); cron-invoked maintenance commands that hit an interactive path.
Related errors
- --description is required when stdin is not a TTY
- No input received from stdin
- cli-secret-empty
- webhook-audit: {e}
- unsupported room visibility '{other}': expected private or p
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/4e631815b5e2d0fe.
Report an issue: GitHub.