{"record":{"id":"63e9b99240655a64","repo":"xai-org/grok-build","slug":"invalidinput-63e9b9","errorCode":"InvalidInput","errorMessage":"path has no parent","messagePattern":"path has no parent","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/agent/subagent/mod.rs","lineNumber":2294,"sourceCode":"            isolation_mode: isolation_mode.map(str::to_string),\n            depth,\n            started_at: meta.started_at.to_rfc3339(),\n            completed_at: meta.completed_at.map(|t| t.to_rfc3339()),\n            status: meta.status.clone(),\n            duration_ms: meta.duration_ms,\n            tool_calls: meta.tool_calls,\n            turns: meta.turns,\n            error: meta.error.clone(),\n            fork_copy_error: meta.fork_copy_error.clone(),\n            resumed_from: meta.resumed_from.clone(),\n        }\n    }\n}\n/// Write via a same-directory temp file and rename, so a crash mid-write\n/// cannot leave a torn `meta.json` or `output.json`.\nfn atomic_write(path: &Path, contents: &str) -> std::io::Result<()> {\n    let parent = path.parent().ok_or_else(|| {\n        std::io::Error::new(std::io::ErrorKind::InvalidInput, \"path has no parent\")\n    })?;\n    std::fs::create_dir_all(parent)?;\n    let tmp = tempfile::NamedTempFile::new_in(parent)?;\n    std::fs::write(tmp.path(), contents)?;\n    tmp.persist(path)?;\n    Ok(())\n}\n/// Write `meta.json`. Returns `true` on success so callers on the resume-pointer\n/// path can gate worktree disposal on a durable write.\nfn write_subagent_meta(dir: &Path, meta: &SubagentMeta) -> bool {\n    let json = match serde_json::to_string_pretty(meta) {\n        Ok(json) => json,\n        Err(e) => {\n            tracing::warn!(error = %e, \"failed to serialize subagent meta\");\n            return false;\n        }\n    };\n    if let Err(e) = atomic_write(&dir.join(\"meta.json\"), &json) {","sourceCodeStart":2276,"sourceCodeEnd":2312,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/agent/subagent/mod.rs#L2276-L2312","documentation":"`atomic_write` in the subagent module persists `meta.json`/`output.json` by writing a same-directory temp file and renaming. If `path.parent()` returns `None` — the path is bare/root-like with no directory component — the function fails with `std::io::Error` of kind `InvalidInput` and message 'path has no parent', because the temp file must be created in the same directory as the target for the rename to be atomic.","triggerScenarios":"Calling `atomic_write` (via subagent meta/output persistence) with a path like `Path::new(\"meta.json\")` or `Path::new(\"/\")` that has no parent directory component.","commonSituations":"A bug where the subagent directory prefix was empty or dropped before joining the filename; constructing the path from a mis-parsed config value; tests passing a bare filename directly.","solutions":["Always pass an absolute path under the subagent's directory (e.g. `<session_dir>/meta.json`)","Join the bare filename onto a real base directory before writing","Pre-validate `path.parent().is_some()` in the caller and error out early with a better message"],"exampleFix":"// before\natomic_write(Path::new(\"meta.json\"), &contents)?;\n// after\nlet path = session_dir.join(\"meta.json\");\natomic_write(&path, &contents)?;","handlingStrategy":"validation","validationCode":"fn ensure_writable(p: &Path) -> Result<(), String> {\n    if p.parent().is_none() {\n        return Err(format!(\"{}: join the filename onto a real directory\", p.display()));\n    }\n    Ok(())\n}","typeGuard":"fn has_parent_dir(p: &Path) -> bool { p.parent().is_some() }","tryCatchPattern":"match atomic_write(&path, &contents) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput && e.to_string() == \"path has no parent\" => {\n        eprintln!(\"meta/output path must include its directory\");\n    }\n    other => other,\n}","preventionTips":["Always construct subagent file paths as base_dir.join(filename)","Never persist with a bare filename","Validate parent existence before atomic writes"],"tags":["io","filesystem","atomic-write","path-validation"],"backgroundTag":"invalid-path-input","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}