neondatabase/neon · error

parse pidfile content to PID

Error message

parse pidfile content to PID

What it means

pid_file::read parses the content of a lock-holding pidfile via parse_pidfile_content; if the bytes are not a plain decimal integer parseable as i32 (empty file, garbage text, truncated write), this error is returned instead of a PID.

Source

Thrown at libs/utils/src/pid_file.rs:161

        LockFileRead::LockedByOtherProcess {
            not_locked_file: _not_locked_file,
            content,
        } => {
            // XXX the read races with the write in claim_pid_file_for_pid().
            // But pids are smaller than a page, so the kernel page cache will lock for us.
            // The only problem is that we might get the old contents here.
            // Can only fix that by implementing some scheme that downgrades the
            // exclusive lock to shared lock in claim_pid_file_for_pid().
            PidFileRead::LockedByOtherProcess(parse_pidfile_content(&content)?)
        }
    };
    Ok(ret)
}

fn parse_pidfile_content(content: &str) -> anyhow::Result<Pid> {
    let pid: i32 = content
        .parse()
        .map_err(|_| anyhow::anyhow!("parse pidfile content to PID"))?;
    if pid < 1 {
        anyhow::bail!("bad value in pidfile '{pid}'");
    }
    Ok(Pid::from_raw(pid))
}

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Inspect the file: cat <pidfile>
  2. If no process holds the lock (service is stopped), remove the stale pidfile and restart
  3. Prevent other tooling from writing to the pidfile path

Example fix

# before
$ cat /var/lib/neon.pid
not-a-pid
# after: with the service stopped, clear the stale file and start
# rm /var/lib/neon.pid
systemctl start neon
Defensive patterns

Strategy: validation

Validate before calling

fn pidfile_content_is_valid(path: &std::path::Path) -> bool {
    std::fs::read_to_string(path)
        .ok()
        .and_then(|c| c.trim().parse::<i32>().ok())
        .is_some_and(|pid| pid >= 1)
}

Type guard

fn is_pidfile_parse_error(err: &anyhow::Error) -> bool {
    err.to_string().contains("parse pidfile content to PID")
}

Try / catch

match pid_file::read(&path) {
    Err(e) if e.to_string().contains("parse pidfile content to PID") => {
        // content is garbage; if no process holds the flock, treat as stale and remove
    }
    other => other?,
}

Prevention

When it happens

Trigger: Reading a pidfile whose content is non-numeric: a file truncated by a crash between create and write_content, overwritten by other tooling, or corrupted on disk.

Common situations: Power loss mid-startup leaving a zero-length pidfile; humans or scripts accidentally writing to the pidfile; disk corruption.

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/465f286dc5262b05. Report an issue: GitHub.