Hmbown/CodeWhale · error

continual harness entry id cannot be empty

Error message

continual harness entry id cannot be empty

What it means

Argument guard in continual_harness remove(): the caller-supplied entry id must be a non-empty string (after trimming) before the harness state is read and journalled. It fires on remove("") or remove(" ") — no state mutation happens.

Solutions

  1. Pass the actual entry id (the h_<uuid> value returned by refine/list).
  2. Validate the id is non-empty before calling remove.

Example fix

// before
harness::remove(ws, "")?;
// after
anyhow::ensure!(!id.trim().is_empty(), "id required");
harness::remove(ws, id)?;
Defensive patterns

Strategy: validation

Validate before calling

let id = id.trim();
if id.is_empty() { return Err(anyhow::anyhow!("entry id required")); }

Type guard

fn has_entry_id(id: &str) -> bool { !id.trim().is_empty() }

Try / catch

match harness::remove(ws, id) {
    Err(e) if e.to_string().contains("id cannot be empty") => report_missing_id(),
    other => other,
}

Prevention

When it happens

Trigger: Calling harness::remove(workspace, "") or with a whitespace-only id.

Common situations: A script with an unset id variable; a UI passing through an empty selection.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/e58786a8e0f73b63. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/continual_harness.rs:138

            content: refinement.content,
            evidence: refinement.evidence,
        };
        state.schema_version = SCHEMA_VERSION;
        state.entries.push(entry.clone());
        save_state(&path, &state)?;
        // Journalled after the state is durable: a logged edit that never
        // landed would be worse than an unlogged one.
        append_journal(&path, "refine", &entry)?;
        Ok(entry)
    })
}

/// Remove one exact entry. Returning the removed entry makes deletion
/// receipts useful without re-reading the state file.
pub fn remove(workspace: &Path, id: &str) -> Result<HarnessEntry> {
    let id = id.trim();
    if id.is_empty() {
        bail!("continual harness entry id cannot be empty");
    }
    let path = state_path_for_write(workspace)?;
    with_write_lock(&path, || {
        let mut state = load_state(&path)?;
        let index = state
            .entries
            .iter()
            .position(|entry| entry.id == id)
            .ok_or_else(|| anyhow!("continual harness has no entry `{id}`"))?;
        let removed = state.entries.remove(index);
        state.schema_version = SCHEMA_VERSION;
        save_state(&path, &state)?;
        // Removal is the edit most worth recording: the entry is gone from
        // state, so the journal is the only place its content survives.
        append_journal(&path, "remove", &removed)?;
        Ok(removed)
    })
}

View on GitHub (pinned to 73e0f67d83)