Hmbown/CodeWhale · error
skill state lock at must be a regular file
Error message
skill state lock at {} must be a regular file What it means
On platforms other than Unix and Windows, validate_state_lock checks only that the lock file's metadata reports it is a regular file. If the path resolves to a directory, FIFO, device, or other special file, the ensure! fails. Like its platform-specific siblings, this guards the integrity of the skill state lock.
Solutions
- Delete the lock path so the application can recreate it as a regular file.
- Verify what exists at the path (`ls -la`) and remove any directory/FIFO/device node found there.
- Run on a supported mainstream platform if the target's filesystem semantics are unknown.
Example fix
// before $ ls ~/.codewhale/skill-state.lock directory // after $ rm -rf ~/.codewhale/skill-state.lock $ codewhale # recreates a regular lock file
Defensive patterns
Strategy: validation
Validate before calling
let md = std::fs::metadata(lock_path)?;
if !md.is_file() {
std::fs::remove_file(lock_path).or_else(|_| std::fs::remove_dir_all(lock_path))?;
} Type guard
fn is_regular_file(p: &std::path::Path) -> bool {
std::fs::metadata(p).map(|m| m.is_file()).unwrap_or(false)
} Prevention
- Keep the skill state directory on a filesystem that supports regular files only (no special nodes).
- Delete stale lock paths after crashes or state resets.
- Avoid creating the lock path manually or via scripts that may mkdir it.
When it happens
Trigger: open_state_lock runs on a non-Unix/non-Windows platform (e.g. wasm or another target) and the lock file at the given path is not a regular file.
Common situations: Running on an unusual target (embedded, wasm, custom platform) where the lock path was pre-created as a directory or special node, or stale/corrupted state left by another tool.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- private sidecar file
- provider catalog lock
- already exists; pass --force to overwrite it
- Android dladdr could not locate the updater's loaded image
- Android dladdr returned an empty loaded-image path
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/92168e7cbbbf9042.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/skill_state.rs:238
#[cfg(windows)]
fn validate_state_lock(path: &Path, file: &fs::File) -> Result<()> {
use std::os::windows::fs::MetadataExt as _;
const FILE_ATTRIBUTE_REPARSE_POINT: u32 = 0x0000_0400;
let metadata = file
.metadata()
.with_context(|| format!("inspect skill state lock at {}", path.display()))?;
anyhow::ensure!(
metadata.is_file() && metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT == 0,
"skill state lock at {} must be a regular, non-reparse file",
path.display()
);
Ok(())
}
#[cfg(all(not(unix), not(windows)))]
fn validate_state_lock(path: &Path, file: &fs::File) -> Result<()> {
anyhow::ensure!(
file.metadata()
.with_context(|| format!("inspect skill state lock at {}", path.display()))?
.is_file(),
"skill state lock at {} must be a regular file",
path.display()
);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
fn fresh() -> (TempDir, SkillStateStore) {
let dir = TempDir::new().unwrap();
let path = dir.path().join(STATE_FILE_NAME);
let store = SkillStateStore::load_from(path).unwrap();View on GitHub (pinned to 433685b202)