xai-org/grok-build · error
InvalidInput
InvalidInput
Error message
path has no parent
What it means
`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.
Source
Thrown at crates/codegen/xai-grok-shell/src/agent/subagent/mod.rs:2294
isolation_mode: isolation_mode.map(str::to_string),
depth,
started_at: meta.started_at.to_rfc3339(),
completed_at: meta.completed_at.map(|t| t.to_rfc3339()),
status: meta.status.clone(),
duration_ms: meta.duration_ms,
tool_calls: meta.tool_calls,
turns: meta.turns,
error: meta.error.clone(),
fork_copy_error: meta.fork_copy_error.clone(),
resumed_from: meta.resumed_from.clone(),
}
}
}
/// Write via a same-directory temp file and rename, so a crash mid-write
/// cannot leave a torn `meta.json` or `output.json`.
fn atomic_write(path: &Path, contents: &str) -> std::io::Result<()> {
let parent = path.parent().ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidInput, "path has no parent")
})?;
std::fs::create_dir_all(parent)?;
let tmp = tempfile::NamedTempFile::new_in(parent)?;
std::fs::write(tmp.path(), contents)?;
tmp.persist(path)?;
Ok(())
}
/// Write `meta.json`. Returns `true` on success so callers on the resume-pointer
/// path can gate worktree disposal on a durable write.
fn write_subagent_meta(dir: &Path, meta: &SubagentMeta) -> bool {
let json = match serde_json::to_string_pretty(meta) {
Ok(json) => json,
Err(e) => {
tracing::warn!(error = %e, "failed to serialize subagent meta");
return false;
}
};
if let Err(e) = atomic_write(&dir.join("meta.json"), &json) {View on GitHub (pinned to bc7f02eddd)
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
Example fix
// before
atomic_write(Path::new("meta.json"), &contents)?;
// after
let path = session_dir.join("meta.json");
atomic_write(&path, &contents)?; Defensive patterns
Strategy: validation
Validate before calling
fn ensure_writable(p: &Path) -> Result<(), String> {
if p.parent().is_none() {
return Err(format!("{}: join the filename onto a real directory", p.display()));
}
Ok(())
} Type guard
fn has_parent_dir(p: &Path) -> bool { p.parent().is_some() } Try / catch
match atomic_write(&path, &contents) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput && e.to_string() == "path has no parent" => {
eprintln!("meta/output path must include its directory");
}
other => other,
} Prevention
- Always construct subagent file paths as base_dir.join(filename)
- Never persist with a bare filename
- Validate parent existence before atomic writes
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to replace {}: {e}
- InvalidInput
- no .git file or directory found at {}
- local workspace cwd must exist and be canonicalizable: {}: {
- local workspace cwd must be an existing directory: {}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/63e9b99240655a64.
Report an issue: GitHub.