Hmbown/CodeWhale · error

Refusing a non-regular settings lock at

Error message

Refusing a non-regular settings lock at {}

What it means

The settings-locking path refuses to acquire a file lock unless the lock file is a regular file. After inspecting the lock path's metadata, anything that is not a regular file (directory, FIFO, device, socket) causes this bail, because fd_lock semantics and permission behavior on non-regular files are unsafe/unreliable. This protects the settings store from being locked through an unexpected filesystem object.

Solutions

  1. Inspect the path with `ls -la` / `stat <settings.toml.lock>` and check its file type
  2. Remove the bogus object: `rm -rf <settings.toml.lock>` (only if you are sure it is not legitimate data)
  3. Retry the operation so a fresh regular lock file is created
  4. If it recurs, audit for software or processes creating non-regular files at that path

Example fix

// before (shell)
ls -la ~/.config/codewhale/settings.toml.lock  # shows a directory/FIFO
// after (shell)
rm -rf ~/.config/codewhale/settings.toml.lock  # remove non-regular object, retry
Defensive patterns

Strategy: validation

Validate before calling

use std::fs;
fn lock_path_is_safe(p: &std::path::Path) -> bool {
    fs::metadata(p).map(|m| m.file_type().is_file()).unwrap_or(true) // absent is fine; will be created
}

Try / catch

match acquire_settings_lock() {
    Ok(lock) => /* proceed */,
    Err(e) if e.to_string().contains("non-regular settings lock") => {
        // ask user to inspect/remove the lock path; do NOT auto-delete blindly
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling any settings read/write path that acquires the settings lock (via fd_lock::RwLock on the lock path) when the path `settings.toml.lock` exists but is a directory, FIFO, socket, or device node rather than a regular file.

Common situations: A user or misconfigured tool replaced the lock file with a directory; a leftover named pipe from a crashed process; tampering/malware planting a non-regular file; tmpfs or container weirdness where the lock was created oddly.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/src/settings.rs:2358

    let lock_file = options
        .open(&lock_path)
        .with_context(|| format!("Failed to open settings lock at {}", lock_path.display()))?;
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt as _;
        lock_file
            .set_permissions(fs::Permissions::from_mode(0o600))
            .with_context(|| {
                format!("Failed to secure settings lock at {}", lock_path.display())
            })?;
    }
    if !lock_file
        .metadata()
        .with_context(|| format!("Failed to inspect settings lock at {}", lock_path.display()))?
        .file_type()
        .is_file()
    {
        anyhow::bail!(
            "Refusing a non-regular settings lock at {}",
            lock_path.display()
        );
    }

    let mut lock = fd_lock::RwLock::new(lock_file);
    let _guard = lock
        .write()
        .with_context(|| format!("Failed to acquire settings lock at {}", lock_path.display()))?;
    operation()
}

/// Refuse to lock through a symlink: a planted `settings.toml.lock -> …` would
/// otherwise let an attacker pick which file we create with our permissions.
fn reject_settings_lock_symlink(lock_path: &Path) -> Result<()> {
    match std::fs::symlink_metadata(lock_path) {
        Ok(metadata) if metadata.file_type().is_symlink() => anyhow::bail!(
            "Refusing a symlinked settings lock at {}",

View on GitHub (pinned to 73e0f67d83)