{"record":{"id":"6d5741692f671d81","repo":"xai-org/grok-build","slug":"local-workspace-cancelled","errorCode":null,"errorMessage":"local workspace cancelled","messagePattern":"local workspace cancelled","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/codegen/xai-grok-pager/src/app/session_startup.rs","lineNumber":563,"sourceCode":"        .map(|p| p.display().to_string())\n        .unwrap_or_else(|| \"<session cwd>\".to_string());\n    let banner = LOCAL_WORKSPACE_BANNER.replace(\"<cwd>\", &cwd_display);\n    eprintln!(\"{banner}\");\n    eprintln!(\"{LOCAL_WORKSPACE_HITL_HINT}\");\n    if local_workspace_ack_satisfied() {\n        return Ok(());\n    }\n    if !stdin_is_terminal {\n        anyhow::bail!(\"{LOCAL_WORKSPACE_ACK_REQUIRED}\");\n    }\n    eprint!(\"Continue with local workspace on this machine? [y/N] \");\n    use std::io::Write;\n    let _ = std::io::stderr().flush();\n    let mut line = String::new();\n    std::io::stdin().read_line(&mut line)?;\n    let ok = matches!(line.trim(), \"y\" | \"Y\" | \"yes\" | \"YES\");\n    if !ok {\n        anyhow::bail!(\"local workspace cancelled\");\n    }\n    write_local_workspace_ack();\n    Ok(())\n}\n/// True when ACK env or ack file already authorizes local workspace.\n#[cfg(feature = \"local-workspace\")]\npub fn local_workspace_ack_satisfied() -> bool {\n    if env_truthy(GROK_CHAT_LOCAL_WORKSPACE_ACK_ENV) {\n        return true;\n    }\n    local_workspace_ack_path().is_some_and(|p| p.is_file())\n}\n/// Persist the first-run local-workspace ACK file (best-effort).\n#[cfg(feature = \"local-workspace\")]\npub fn write_local_workspace_ack() {\n    if let Some(path) = local_workspace_ack_path() {\n        if let Some(parent) = path.parent() {\n            let _ = std::fs::create_dir_all(parent);","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-pager/src/app/session_startup.rs#L545-L581","documentation":"This error is raised during the interactive local-workspace consent gate in `emit_local_workspace_startup_ux_with`. When the user is prompted to acknowledge the risks of enabling the local workspace (a y/Y/yes/YES confirmation read from stdin), any other input is treated as a refusal, and the startup flow aborts with this bail. It is an intentional cancellation path, not an unexpected failure — the library requires explicit opt-in to the `local-workspace` feature before continuing startup.","triggerScenarios":"Running the CLI in a non-TTY context where `local_workspace_non_tty_requires_ack` prompts via stdin and the user (or an automated pipe/script) sends anything other than 'y', 'Y', 'yes', or 'YES' as the first line of stdin; also pressing Enter or typing 'no'/'n' at the local-workspace acknowledgment prompt.","commonSituations":"Piping commands or heredocs into the CLI whose first line is not the confirmation string; running under CI or a process manager where stdin is empty or closed so read_line returns an empty line; a human typing 'ok', 'y ' with trailing chars is trimmed fine but 'no' aborts; forgetting that local workspace requires the explicit ack (env var or ack file).","solutions":["Re-run the command and answer the local-workspace confirmation prompt with exactly 'y', 'Y', 'yes', or 'YES'.","Pre-authorize the session so the prompt is skipped: set the ACK environment variable or create the ack file that `write_local_workspace_ack()`/the `ack env or ack file` check accepts.","If running non-interactively (CI/scripts), feed 'y' as the first stdin line, e.g. `echo y | xai-grok ...`, or pre-create the ack file.","If you did not intend to enable the local workspace, pass flags/options that avoid the local-workspace path entirely instead of declining the prompt."],"exampleFix":"// before: script hangs/aborts because stdin is empty\nxai-grok --local-workspace < /dev/null\n// after: pre-authorize or answer the prompt\necho y | xai-grok --local-workspace\n# or, better, pre-create the ack file once:\n# write_local_workspace_ack() equivalent, or set the ACK env var","handlingStrategy":"validation","validationCode":"// Pre-check: ensure an explicit ack exists so the interactive prompt is skipped.\nuse std::path::Path;\nfn local_workspace_ack_present(ack_file: &str, ack_env: Option<&str>) -> bool {\n    std::env::var_os(ack_env.unwrap_or(\"XAI_GROK_LOCAL_WS_ACK\")).is_some()\n        || Path::new(ack_file).exists()\n}\n// If false and stdin is not a TTY, pass `y` on stdin or pre-create the ack file.","typeGuard":"fn is_affirmative(input: &str) -> bool {\n    matches!(input.trim(), \"y\" | \"Y\" | \"yes\" | \"YES\")\n}","tryCatchPattern":"match run_startup() {\n    Err(e) if e.to_string().contains(\"local workspace cancelled\") => {\n        eprintln!(\"Startup aborted: local workspace requires explicit y/N acknowledgment.\");\n        std::process::exit(2);\n    }\n    Err(e) => return Err(e),\n    Ok(v) => v,\n}","preventionTips":["Pre-authorize via the ACK env var or ack file before running non-interactively.","Never pipe a script into the CLI without making 'y' the first stdin line when the prompt will appear.","Check whether stdin is a TTY and warn the user before entering the local-workspace flow.","Treat this error as a user decision, not a bug — exit cleanly with a clear message."],"tags":["cli","local-workspace","user-cancellation","stdin-prompt"],"backgroundTag":"local-workspace-ack-required","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}