Hmbown/CodeWhale · error

Refusing a symlinked settings lock at {}

Error message

Refusing a symlinked settings lock at {}

What it means

Settings lock hardening: symlink_metadata showed settings.toml.lock is a symlink. Locking through it would let whoever planted the link choose which file gets created/locked with the process's owner-only permissions, so the lock is refused and the path named.

Source

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

    {
        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 {}",
            lock_path.display()
        ),
        Ok(_) | Err(_) => Ok(()),
    }
}

/// Replace `path` with `body` by writing an adjacent temporary file and
/// renaming it into place.
///
/// A direct `fs::write` truncates first, so any concurrent reader — another
/// Codewhale process, an editor, a `cat` — can observe a half-written file and
/// parse it as truncated TOML, silently losing every key past the tear. A
/// same-directory temp file plus the platform's replace primitive makes the
/// swap atomic for readers: they see either the whole previous file or the
/// whole new one.
///
/// The temp file inherits the existing file's permission bits when there is one

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Remove the symlinked settings.toml.lock
  2. Retry the settings operation
Defensive patterns

Strategy: type-guard

When it happens

Trigger: Thrown at crates/tui/src/settings.rs:2166 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/b671f7b1f9d81766. Report an issue: GitHub.