Hmbown/CodeWhale · error

external credential consent was not saved: non-interactive…

Error message

external credential consent was not saved: non-interactive use requires explicit --yes after reviewing the preview

What it means

The consent confirmation refuses to save when stdin is not a TTY and `--yes` was not passed. Because a non-interactive caller cannot answer the yes/no prompt, the flow bails rather than silently skipping consent.

Solutions

  1. Review the printed preview lines, then re-run with `--yes` to record consent
  2. Or run the command interactively in a terminal to answer the prompt

Example fix

// before
codewhale auth external --provider grok --mode read-only < /dev/null
// after
codewhale auth external --provider grok --mode read-only --yes < /dev/null
Defensive patterns

Strategy: validation

Validate before calling

if [ ! -t 0 ] && ! grep -q -- '--yes' <<< "$flags"; then echo "non-interactive: add --yes"; exit 1; fi

Prevention

When it happens

Trigger: Running the external credential consent command from a pipe, CI job, or subprocess (stdin not a terminal) without `--yes`.

Common situations: Scripted setup pipelines; docker/CI runs; invoking via tools that detach stdin; forgotten `--yes` in automation that worked interactively.

Understand the failure class

Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/232c4793f797c9f3. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/lib.rs:4332

            "  access: read_only ({})",
            codewhale_config::EXTERNAL_CREDENTIAL_READ_ONLY_SEMANTICS
        ),
        "  managed: unavailable (no reviewed schema-safe preservation adapter)".to_string(),
        format!(
            "  revoke: codewhale auth external-revoke --provider {}",
            provider.as_str()
        ),
    ]
}

fn confirm_external_consent(yes: bool) -> Result<()> {
    use std::io::IsTerminal;

    if yes {
        return Ok(());
    }
    if !std::io::stdin().is_terminal() {
        bail!(
            "external credential consent was not saved: non-interactive use requires explicit --yes after reviewing the preview"
        );
    }
    confirm_external_consent_answer(&mut std::io::stdin().lock(), &mut std::io::stdout().lock())
}

fn confirm_external_consent_answer(
    reader: &mut impl std::io::BufRead,
    writer: &mut impl std::io::Write,
) -> Result<()> {
    write!(writer, "Type 'yes' to grant this exact read-only access: ")?;
    writer.flush()?;
    let mut answer = String::new();
    reader
        .read_line(&mut answer)
        .context("reading external credential consent confirmation")?;
    if answer.trim() != "yes" {
        bail!("external credential consent cancelled; no configuration was changed");

View on GitHub (pinned to 73e0f67d83)