{"record":{"id":"1a051b01c35446af","repo":"neondatabase/neon","slug":"file-is-already-locked","errorCode":null,"errorMessage":"file is already locked","messagePattern":"file is already locked","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/utils/src/lock_file.rs","lineNumber":75,"sourceCode":"/// The exclusive lock is released when dropping the returned handle.\n///\n/// It is not an error if the file already exists.\n/// It is an error if the file is already locked.\npub fn create_exclusive(lock_file_path: &Utf8Path) -> anyhow::Result<UnwrittenLockFile> {\n    let lock_file = fs::OpenOptions::new()\n        .create(true) // O_CREAT\n        .truncate(true)\n        .write(true)\n        .open(lock_file_path)\n        .context(\"open lock file\")?;\n\n    let res = Flock::lock(lock_file, FlockArg::LockExclusiveNonblock);\n    match res {\n        Ok(lock_file) => Ok(UnwrittenLockFile {\n            path: lock_file_path.to_owned(),\n            file: lock_file,\n        }),\n        Err((_, EAGAIN)) => anyhow::bail!(\"file is already locked\"),\n        Err((_, e)) => Err(e).context(\"flock error\"),\n    }\n}\n\n/// Returned by [`read_and_hold_lock_file`].\n/// Check out the [`pid_file`](crate::pid_file) module for what the variants mean\n/// and potential caveats if the lock files that are used to store PIDs.\npub enum LockFileRead {\n    /// No file exists at the given path.\n    NotExist,\n    /// No other process held the lock file, so we grabbed an flock\n    /// on it and read its contents.\n    /// Release the flock by dropping the [`LockFileGuard`].\n    NotHeldByAnyProcess(LockFileGuard, String),\n    /// The file exists but another process was holding an flock on it.\n    LockedByOtherProcess {\n        not_locked_file: fs::File,\n        content: String,","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/utils/src/lock_file.rs#L57-L93","documentation":"lock_file::create_exclusive opens the file and takes a non-blocking exclusive flock (LOCK_EX|LOCK_NB); EAGAIN means another process currently holds the lock. This is the single-instance guard used for pidfiles and data dirs, so the error is by design, not corruption.","triggerScenarios":"Calling claim_for_current_process / create_exclusive on a pidfile or lockfile while another process holds it: a second pageserver on the same data dir, a duplicate safekeeper, or a leftover process that never exited.","commonSituations":"Accidentally starting the service twice; stale process from a previous run; test harnesses sharing a data directory in parallel; manually running the binary while systemd already has it up.","solutions":["Read the lock/pidfile content to find the holder's PID, verify with ps, and stop it if stale","Check systemd/supervisor for duplicate units: systemctl status <unit>","Give each instance its own data/pidfile path"],"exampleFix":"# before: second instance started while first is running\nsystemctl start neon-pageserver && neon_pageserver --pid-file=/var/lib/neon.pid\n# after: stop the existing holder first\nkill $(cat /var/lib/neon.pid)   # or: systemctl stop neon-pageserver","handlingStrategy":"validation","validationCode":"use utils::pid_file;\n\nmatch pid_file::read(&path)? {\n    pid_file::PidFileRead::LockedByOtherProcess(pid) => {\n        anyhow::bail!(\"another instance is running as pid {pid}\");\n    }\n    pid_file::PidFileRead::NotExist | pid_file::PidFileRead::NotHeldByAnyProcess(_) => {\n        // safe to claim\n    }\n}","typeGuard":"fn is_already_locked_error(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"file is already locked\")\n}","tryCatchPattern":"match lock_file::create_exclusive(&path) {\n    Err(e) if e.to_string().contains(\"file is already locked\") => {\n        // read_and_hold_lock_file(&path) yields the holder's content/PID; exit with a clear message\n    }\n    other => other?,\n}","preventionTips":["Run services under a supervisor that guarantees a single instance","Use per-instance pidfile paths in test harnesses","Always drop lock guards cleanly on shutdown"],"tags":["rust","filesystem","locking","single-instance"],"backgroundTag":"file-already-locked","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}