{"record":{"id":"646cbf454c54eab8","repo":"xai-org/grok-build","slug":"single-e","errorCode":null,"errorMessage":"--single: {e}","messagePattern":"--single: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-pager/src/headless/cli.rs","lineNumber":46,"sourceCode":"}\n\n#[derive(Debug, Clone)]\npub enum HeadlessPrompt {\n    Text(String),\n    Blocks(Vec<acp::ContentBlock>),\n}\n\nimpl HeadlessPrompt {\n    /// Build from mutually-exclusive CLI prompt args. `None` means interactive mode.\n    pub fn from_args(\n        single: Option<&str>,\n        prompt_json: Option<&str>,\n        prompt_file: Option<&Path>,\n    ) -> anyhow::Result<Option<Self>> {\n        if let Some(text) = single {\n            Self::from_text(text)\n                .map(Some)\n                .map_err(|e| anyhow::anyhow!(\"--single: {e}\"))\n        } else if let Some(json_str) = prompt_json {\n            Self::from_json(json_str)\n                .map(Some)\n                .map_err(|e| anyhow::anyhow!(\"--prompt-json: {e}\"))\n        } else if let Some(path) = prompt_file {\n            Self::from_file(path).map(Some)\n        } else {\n            Ok(None)\n        }\n    }\n\n    /// `.json` files are parsed as content blocks, everything else as text.\n    pub fn from_file(path: &Path) -> anyhow::Result<Self> {\n        let content = std::fs::read_to_string(path)\n            .map_err(|e| anyhow::anyhow!(\"Failed to read '{}': {e}\", path.display()))?;\n\n        let context = |e| anyhow::anyhow!(\"'{}': {e}\", path.display());\n        if path.extension().and_then(|e| e.to_str()) == Some(\"json\") {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-pager/src/headless/cli.rs#L28-L64","documentation":"PromptSource::from_args wraps failures of Self::from_text(text) as '--single: {e}'. The --single flag's raw text could not be converted into a prompt source (e.g. empty text or content that fails the text prompt invariants).","triggerScenarios":"Calling from_args with single=Some(text) where from_text rejects the input — typically an empty or whitespace-only prompt string.","commonSituations":"Shell variable holding the prompt expands to empty; script passes \"\" when the prompt file was missing; whitespace-only flag value from templating.","solutions":["Ensure a non-empty prompt string is passed to --single","Guard the calling script: fail early if the prompt variable is empty","Trim intended whitespace-only input and treat it as a usage error","Use --prompt-file instead for long or generated prompts"],"exampleFix":"# before\npager --single \"$PROMPT\"   # PROMPT may be empty\n# after\n: \"${PROMPT:?PROMPT is empty}\" && pager --single \"$PROMPT\"","handlingStrategy":"validation","validationCode":"if single.trim().is_empty() {\n    eprintln!(\"--single requires a non-empty prompt\");\n    std::process::exit(2);\n}","typeGuard":"fn is_usable_prompt(s: &str) -> bool { !s.trim().is_empty() }","tryCatchPattern":"match PromptSource::from_args(single.as_deref(), None, None) {\n    Ok(Some(src)) => src,\n    Ok(None) => { eprintln!(\"no prompt given\"); std::process::exit(2); }\n    Err(e) => { eprintln!(\"{e:#}\"); std::process::exit(2); }\n}","preventionTips":["Fail fast in scripts when the prompt variable is empty","Trim and check prompt strings before invoking","Prefer --prompt-file for generated or long prompts","Test CLI wrappers with an empty-input case"],"tags":["cli","prompt","validation"],"backgroundTag":"empty-prompt-input","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}