xai-org/grok-build · error

{LOCAL_WORKSPACE_ACK_REQUIRED}

Error message

{LOCAL_WORKSPACE_ACK_REQUIRED}

What it means

Local workspace activation is gated by a human-in-the-loop acknowledgement. `emit_local_workspace_startup_ux_with` prints a banner, and if no prior ACK exists (GROK_CHAT_LOCAL_WORKSPACE_ACK truthy or ack file present) and stdin is not a terminal, it fails closed with `LOCAL_WORKSPACE_ACK_REQUIRED` (session_startup.rs:554) rather than proceeding without consent.

Source

Thrown at crates/codegen/xai-grok-pager/src/app/session_startup.rs:554

/// Testable UX gate: `stdin_is_terminal` is injected.
#[cfg(feature = "local-workspace")]
pub fn emit_local_workspace_startup_ux_with(
    cfg: &LocalWorkspaceConfig,
    stdin_is_terminal: bool,
) -> anyhow::Result<()> {
    let cwd_display = cfg
        .cwd
        .as_ref()
        .map(|p| p.display().to_string())
        .unwrap_or_else(|| "<session cwd>".to_string());
    let banner = LOCAL_WORKSPACE_BANNER.replace("<cwd>", &cwd_display);
    eprintln!("{banner}");
    eprintln!("{LOCAL_WORKSPACE_HITL_HINT}");
    if local_workspace_ack_satisfied() {
        return Ok(());
    }
    if !stdin_is_terminal {
        anyhow::bail!("{LOCAL_WORKSPACE_ACK_REQUIRED}");
    }
    eprint!("Continue with local workspace on this machine? [y/N] ");
    use std::io::Write;
    let _ = std::io::stderr().flush();
    let mut line = String::new();
    std::io::stdin().read_line(&mut line)?;
    let ok = matches!(line.trim(), "y" | "Y" | "yes" | "YES");
    if !ok {
        anyhow::bail!("local workspace cancelled");
    }
    write_local_workspace_ack();
    Ok(())
}
/// True when ACK env or ack file already authorizes local workspace.
#[cfg(feature = "local-workspace")]
pub fn local_workspace_ack_satisfied() -> bool {
    if env_truthy(GROK_CHAT_LOCAL_WORKSPACE_ACK_ENV) {
        return true;

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Set GROK_CHAT_LOCAL_WORKSPACE_ACK=1 in the environment for non-interactive runs
  2. Answer the interactive `Continue with local workspace? [y/N]` prompt once in a TTY so the ack file persists
  3. Run interactively in a terminal for the first activation
  4. Pre-create the ack file at the path `local_workspace_ack_path()` expects

Example fix

// before
grok-pager --chat --local-workspace-own < input.txt
// after
GROK_CHAT_LOCAL_WORKSPACE_ACK=1 grok-pager --chat --local-workspace-own < input.txt
Defensive patterns

Strategy: fallback

Validate before calling

fn ack_ready() -> bool {
    std::env::var("GROK_CHAT_LOCAL_WORKSPACE_ACK").ok().as_deref() == Some("1")
        || std::path::Path::new(&ack_file_path()).is_file()
}

Try / catch

match run_with_local_workspace(args) {
    Err(e) if e.to_string().contains("ACK") => {
        eprintln!("non-interactive run: set GROK_CHAT_LOCAL_WORKSPACE_ACK=1 after reviewing the banner: {e}");
        std::process::exit(2);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running the chat CLI with a local workspace enabled in non-interactive contexts: CI jobs, piped/redirected stdin, `nohup`, systemd services, docker exec without -t, when neither the ACK env var nor the ack file exists.

Common situations: First local-workspace run inside CI; scheduling the tool where stdin is /dev/null; running via a wrapper that detaches the TTY before the interactive confirm could be answered.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/e9401357a14d5b2e. Report an issue: GitHub.