{"record":{"id":"6cfaf3b61e59dca2","repo":"nikivdev/code","slug":"plan-body-is-empty","errorCode":null,"errorMessage":"plan body is empty","messagePattern":"plan body is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/codex_runtime.rs","lineNumber":1244,"sourceCode":"        .ok()\n        .or_else(|| env::var(\"FLOW_CODEX_RUNTIME_STATE\").ok())?;\n    let path = PathBuf::from(raw_path);\n    let raw = fs::read(path).ok()?;\n    serde_json::from_slice::<CodexRuntimeState>(&raw).ok()\n}\n\npub fn write_plan_from_stdin(\n    title: Option<&str>,\n    stem: Option<&str>,\n    dir: Option<&str>,\n    source_session: Option<&str>,\n) -> Result<PathBuf> {\n    let mut body = String::new();\n    io::stdin()\n        .read_to_string(&mut body)\n        .context(\"failed to read plan body from stdin\")?;\n    if body.trim().is_empty() {\n        bail!(\"plan body is empty\");\n    }\n\n    let root = resolve_plan_root(dir);\n    fs::create_dir_all(&root)?;\n\n    let resolved_title = title\n        .map(str::trim)\n        .filter(|value| !value.is_empty())\n        .map(ToOwned::to_owned)\n        .unwrap_or_else(|| derive_plan_title(&body));\n    let mut resolved_stem = stem\n        .map(str::trim)\n        .filter(|value| !value.is_empty())\n        .map(ToOwned::to_owned)\n        .unwrap_or_else(|| slugify(&resolved_title));\n    if !resolved_stem.ends_with(\"-plan\") {\n        resolved_stem.push_str(\"-plan\");\n    }","sourceCodeStart":1226,"sourceCodeEnd":1262,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/codex_runtime.rs#L1226-L1262","documentation":"This function reads a plan document from stdin (io::stdin().read_to_string) and, after successfully reading it, checks that the trimmed body is non-empty. An empty or whitespace-only stdin input produces this error, because a plan file with no content would be invalid. Note the preceding read is wrapped with context 'failed to read plan body from stdin', so this bail specifically means stdin was readable but blank.","triggerScenarios":"Invoking the plan-creation routine with stdin closed, redirected from an empty file (`< /dev/null` or `< empty.txt`), or piped from a command that produced no output (`echo -n '' | tool plan ...`).","commonSituations":"Forgetting to pipe the plan content and running the command in a non-interactive context where stdin is /dev/null (CI jobs, cron); an upstream generator failing silently and emitting nothing; heredocs left empty; paste failures in scripted pipelines.","solutions":["Pipe the actual plan content into the command, e.g. `cat plan.md | tool plan --title \"...\"`.","Check the upstream command that feeds stdin — it may be failing or producing empty output.","In CI/cron, ensure stdin is connected to a file with content rather than /dev/null.","Add a pre-check in your pipeline: fail early if the generated plan body is empty before invoking the tool."],"exampleFix":"// before\ntool plan --title \"Refactor\" < /dev/null\n// after\ntool plan --title \"Refactor\" < ./plans/refactor.md","handlingStrategy":"validation","validationCode":"let mut body = String::new();\nio::stdin().read_to_string(&mut body)?;\nif body.trim().is_empty() {\n    return Err(\"refusing to call: plan body from stdin is empty\".into());\n}","typeGuard":"fn has_content(s: &str) -> bool { !s.trim().is_empty() }","tryCatchPattern":"match write_plan_from_stdin(dir, title) {\n    Err(e) if e.to_string().contains(\"plan body is empty\") => {\n        eprintln!(\"stdin was empty — check the upstream command/file feeding the pipe.\");\n    }\n    other => other?,\n}","preventionTips":["Always verify the file or upstream command piped into stdin actually has content.","In CI/cron, redirect stdin from a real file, not /dev/null.","Check upstream generators exit 0 and produce output before piping them in."],"tags":["stdin","input-validation","empty-input","cli"],"backgroundTag":"empty-stdin-input","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}