Hmbown/CodeWhale · error
continual harness state has no parent
Error message
continual harness state has no parent: {} What it means
save_state persists the harness state atomically: it needs the state file's parent directory to create it and to place the UUID-named temp file next to the target. Path::parent returns None only for pathological paths (bare file name with no directory component), so this error indicates the caller passed a relative bare filename instead of a path with a directory component.
Solutions
- Pass a path that includes a directory, e.g. PathBuf::from("./state.json") or an absolute path via std::env::current_dir().join(file).
- Normalize the path with std::fs::canonicalize (or join with the cwd) before handing it to the harness.
- Fix the config/CLI argument that supplies the state path so it is not a bare filename.
Example fix
// before
let path = Path::new("state.json");
harness.refine(&path, ...)?; // no parent
// after
let path = std::env::current_dir()?.join("state.json");
harness.refine(&path, ...)?; Defensive patterns
Strategy: validation
Validate before calling
fn absolute_state_path(raw: &str) -> std::path::PathBuf {
let p = std::path::Path::new(raw);
if p.parent().map_or(true, |p| p.as_os_str().is_empty()) {
std::env::current_dir().unwrap_or_default().join(p)
} else {
p.to_path_buf()
}
} Try / catch
match result {
Err(e) if e.to_string().contains("has no parent") => {
eprintln!("state path must include a directory, e.g. ./state.json");
}
other => other?,
} Prevention
- Always pass absolute or at least directory-qualified state paths.
- Resolve configured paths against the working directory or a data dir at startup.
- Canonicalize user-supplied paths before handing them to persistence APIs.
When it happens
Trigger: Calling refine or remove with a state path that has no parent directory component, e.g. passing 'state.json' instead of './state.json' or an absolute path.
Common situations: Constructing the path from a bare filename constant; environment/config supplying a filename without a directory; tests passing "state.json" directly.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Codewhale credentials directory cannot be a volume root
- Codewhale-owned xAI OAuth path has the wrong filesystem type
- external credential path must resolve to an absolute path
- invalid on-disk package directory for skill
- path has no parent
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/0deb5d947ae6c513.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/continual_harness.rs:279
path.display(),
state.schema_version,
SCHEMA_VERSION
);
}
if state.entries.len() > MAX_ENTRIES {
bail!(
"continual harness state {} has {} entries; maximum is {MAX_ENTRIES}",
path.display(),
state.entries.len()
);
}
Ok(state)
}
fn save_state(path: &Path, state: &HarnessState) -> Result<()> {
let parent = path
.parent()
.ok_or_else(|| anyhow!("continual harness state has no parent: {}", path.display()))?;
fs::create_dir_all(parent)
.with_context(|| format!("create continual harness directory {}", parent.display()))?;
let payload = serde_json::to_vec_pretty(state)?;
let tmp = path.with_extension(format!("{}.tmp", Uuid::new_v4().simple()));
fs::write(&tmp, payload)
.with_context(|| format!("write continual harness temporary state {}", tmp.display()))?;
if let Err(error) = fs::rename(&tmp, path) {
let _ = fs::remove_file(&tmp);
return Err(error).with_context(|| {
format!(
"publish continual harness state {} -> {}",
tmp.display(),
path.display()
)
});
}
Ok(())
}View on GitHub (pinned to 433685b202)