{"record":{"id":"eaf3f905a776caa1","repo":"xai-org/grok-build","slug":"chat-mode-fork-conflict","errorCode":null,"errorMessage":"{CHAT_MODE_FORK_CONFLICT}","messagePattern":"\\{CHAT_MODE_FORK_CONFLICT\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-pager/src/app/session_startup.rs","lineNumber":821,"sourceCode":"/// Materialize CLI intent into a concrete startup plan (I/O + remote restore).\npub async fn materialize_startup(\n    ctx: MaterializeCtx,\n    intent: SessionStartupIntent,\n) -> anyhow::Result<MaterializedStartup> {\n    let cwd = std::env::current_dir()\n        .map_err(|e| anyhow::anyhow!(\"Failed to get cwd: {e}\"))?\n        .to_string_lossy()\n        .to_string();\n    materialize_startup_for_cwd(ctx, intent, &cwd).await\n}\n/// Same as [`materialize_startup`] but with an explicit process cwd (tests, headless).\npub async fn materialize_startup_for_cwd(\n    ctx: MaterializeCtx,\n    intent: SessionStartupIntent,\n    cwd: &str,\n) -> anyhow::Result<MaterializedStartup> {\n    if ctx.chat_mode && matches!(intent, SessionStartupIntent::ForkFrom { .. }) {\n        anyhow::bail!(\"{CHAT_MODE_FORK_CONFLICT}\");\n    }\n    match intent {\n        SessionStartupIntent::NewAuto => Ok(MaterializedStartup::NewAuto),\n        SessionStartupIntent::NewWithId { session_id } => {\n            if !ctx.has_worktree {\n                ensure_session_id_available(&session_id, cwd)?;\n            } else if uuid::Uuid::try_parse(&session_id).is_err() {\n                anyhow::bail!(\"Error: --session-id must be a valid UUID (got '{session_id}').\");\n            }\n            Ok(MaterializedStartup::NewWithId { session_id })\n        }\n        SessionStartupIntent::Resume {\n            session_id: None,\n            most_recent_for_cwd: true,\n        } => {\n            if ctx.chat_mode {\n                anyhow::bail!(\"chat-mode resume requires a build with the `chat` cargo feature\");\n            }","sourceCodeStart":803,"sourceCodeEnd":839,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-pager/src/app/session_startup.rs#L803-L839","documentation":"`materialize_startup_for_cwd` rejects combining chat mode with a fork intent. The `CHAT_MODE_FORK_CONFLICT` constant message is bailed when `ctx.chat_mode` is true and the incoming `SessionStartupIntent` is `ForkFrom { .. }`, because forking is not a supported operation while starting in chat mode. This is a mutually-exclusive-options validation performed before any I/O or remote restore happens.","triggerScenarios":"Invoking `materialize_startup`/`materialize_startup_for_cwd` with `MaterializeCtx { chat_mode: true, .. }` and `intent == SessionStartupIntent::ForkFrom { .. }` — i.e. the CLI was launched with both chat-mode and fork flags (e.g. `--chat` together with `--fork`/fork-from-session options).","commonSituations":"Alias or script that hard-codes `--chat` while the user adds a `--fork` flag; reusing a command template that included chat mode when trying to fork a previous session; misunderstanding that chat mode supports only NewAuto/NewWithId/Resume, not forks.","solutions":["Remove the fork flags and keep chat mode, or drop chat mode if forking is what you need — pass only one of the two.","If you need both behaviors, fork in a normal (non-chat) startup first, then start a chat session on the result.","Check wrapper scripts/aliases for a hard-coded `--chat` flag and make fork paths skip it.","Consult the CLI help to see which intents chat mode supports and choose a compatible intent (NewAuto, NewWithId, or Resume)."],"exampleFix":"// before: flags conflict\nxai-grok --chat --fork-from <session-id>\n// after: pick one intent\nxai-grok --fork-from <session-id>   # fork without chat mode\n# or\nxai-grok --chat                     # plain chat session","handlingStrategy":"validation","validationCode":"// Validate flag combinations in your wrapper before invoking the CLI.\nfn flags_conflict(chat_mode: bool, fork_from: Option<&str>) -> bool {\n    chat_mode && fork_from.is_some()\n}\nif flags_conflict(args.chat, args.fork_from.as_deref()) {\n    eprintln!(\"--chat cannot be combined with fork; choose one.\");\n    std::process::exit(2);\n}","typeGuard":null,"tryCatchPattern":"match materialize_startup(ctx).await {\n    Err(e) if e.to_string().contains(\"CHAT_MODE_FORK_CONFLICT\")\n           || e.to_string().to_lowercase().contains(\"fork\") => {\n        eprintln!(\"Chat mode and fork are mutually exclusive; re-run with only one.\");\n        std::process::exit(2);\n    }\n    other => other?,\n}","preventionTips":["Keep CLI arg parsing in one place that enforces mutual exclusivity up front.","Audit aliases/wrapper scripts for a hard-coded --chat flag.","In scripts, branch: fork in normal mode first, then optionally start chat on the result.","Show CLI help/intent support matrix when validating user input."],"tags":["cli","chat-mode","fork","conflicting-flags","validation"],"backgroundTag":"conflicting-cli-options","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}