tokio-rs/tokio · error · io::Error

unexpected xucred version from LOCAL_PEERCRED

Error message

unexpected xucred version from LOCAL_PEERCRED

What it means

Thrown by tokio's FreeBSD peer-credential retrieval for Unix sockets. After reading LOCAL_PEERCRED into an xucred struct, tokio verifies cr_version equals XUCRED_VERSION; a mismatch means the kernel returned a credential layout tokio cannot interpret safely. It mirrors getpeereid(3) which rejects unknown credential versions.

Source

Thrown at tokio/src/net/unix/ucred.rs:263

                &mut len,
            );

            if ret != 0 {
                return Err(io::Error::last_os_error());
            }
            if len as usize != size_of::<xucred>() {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "unexpected xucred size from LOCAL_PEERCRED",
                ));
            }

            let xucred = xucred.assume_init();

            // Match `getpeereid(3)` and reject any `xucred` whose version we
            // don't know how to interpret.
            if xucred.cr_version != XUCRED_VERSION {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "unexpected xucred version from LOCAL_PEERCRED",
                ));
            }

            // `cr_pid` is populated by the kernel since FreeBSD 13. PID 0 is
            // the kernel scheduler and never a real userland peer, so we
            // surface it as `None` rather than a misleading `Some(0)`.
            let pid = match xucred.cr_pid__c_anonymous_union.cr_pid {
                0 => None,
                p => Some(p as unix::pid_t),
            };

            // `xucred` carries the effective uid in `cr_uid` and the effective
            // gid in `cr_groups[0]`, matching what `getpeereid(2)` returns.
            Ok(super::UCred {
                uid: xucred.cr_uid as unix::uid_t,
                gid: xucred.cr_groups[0] as unix::gid_t,

View on GitHub (pinned to 625954f365)

Solutions

  1. Rebuild tokio (and your crate) on the exact FreeBSD version where it runs so XUCRED_VERSION matches the kernel.
  2. Upgrade tokio to a release that supports the xucred version your kernel emits.
  3. Avoid peer_cred on the affected host and obtain peer credentials through an out-of-band mechanism (e.g. SO_PEERCRED-equivalent handshake in your protocol).
  4. If pinned on a mismatched FreeBSD, run inside a jail/kernel of a supported version.

Example fix

// before
let cred = stream.peer_cred()?;
// after (guard against the platform mismatch)
let cred = match stream.peer_cred() {
    Ok(c) => c,
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        return Err(Box::new(e));
    }
    Err(e) => return Err(Box::new(e)),
};
Defensive patterns

Strategy: try-catch

Validate before calling

// No pre-call validation possible; kernel version mismatch surfaces at runtime.
// Document the supported FreeBSD version range for your binary.

Try / catch

match stream.peer_cred() {
    Ok(cred) => { /* use cred */ },
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        // xucred size or version mismatch on FreeBSD
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling UCred::from_LOCAL_PEERCRED (via UnixStream::peer_cred / UnixListener peer credential APIs) on FreeBSD where the kernel's xucred version differs from the constant tokio was compiled against.

Common situations: Running a tokio binary built against one FreeBSD major version on a different major version whose xucred ABI changed; running on an older FreeBSD that reports a lower cr_version; cross-version jail or compatibility layers that synthesize credentials.

Related errors


AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11). Data as JSON: /api/errors/5831fc0702c69535. Report an issue: GitHub.