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.

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.

Appendix: 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)