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

  1. Pass a path that includes a directory, e.g. PathBuf::from("./state.json") or an absolute path via std::env::current_dir().join(file).
  2. Normalize the path with std::fs::canonicalize (or join with the cwd) before handing it to the harness.
  3. 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

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


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)