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

unexpected xucred size from LOCAL_PEERCRED

Error message

unexpected xucred size from LOCAL_PEERCRED

What it means

On Apple platforms, getsockopt(LOCAL_PEERCRED) writes an xucred struct; tokio asserts that the returned len equals size_of::<xucred>(). If the kernel wrote a different number of bytes (struct layout/size changed across OS versions), tokio returns InvalidData 'unexpected xucred size from LOCAL_PEERCRED'. A subsequent check also rejects unknown cr_version. It is a defensive guard against ABI drift in the BSD xucred structure.

Source

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

        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut xucred = MaybeUninit::<xucred>::zeroed();
            let mut len = size_of::<xucred>() as socklen_t;

            let ret = getsockopt(
                raw_fd,
                SOL_LOCAL,
                LOCAL_PEERCRED,
                xucred.as_mut_ptr() as *mut c_void,
                &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

View on GitHub (pinned to 625954f365)

Solutions

  1. Rebuild tokio (and its socket2/libc deps) against the SDK matching the running kernel so size_of::<xucred>() matches.
  2. Upgrade tokio to a release that supports the current OS xucred layout, or downgrade the OS to a compatible version.
  3. Treat the error as non-fatal: fall back to getpeereid(3) or skip peer-credential checks on this platform.
  4. File an upstream issue if the size mismatch appears on a stable OS release — it may be a tokio/libc binding bug.

Example fix

// before
let cred = peer_cred.get(&stream).await?; // InvalidData on new macOS

// after
let cred = match peer_cred.get(&stream).await {
    Ok(c) => Some(c),
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        tracing::warn!("LOCAL_PEERCRED size mismatch: {e}; skipping peer creds");
        None
    }
    Err(e) => return Err(e.into()),
};
Defensive patterns

Strategy: fallback

Validate before calling

// No portable pre-check; the size mismatch is an OS/ABI condition.
// Gate peer-cred calls behind a platform/version probe if you know the range:
#[cfg(all(unix, any(target_os = "macos", target_os = "freebsd")))]
fn try_peer_cred(stream: &UnixStream) -> Option<UCred> {
    peer_cred.get(stream).await.ok()
}

Type guard

fn is_xucred_size_mismatch(e: &io::Error) -> bool {
    e.kind() == io::ErrorKind::InvalidData
        && e.to_string().contains("xucred size")
}

Try / catch

match peer_cred.get(&stream).await {
    Ok(c) => Ok(c),
    Err(e) if e.to_string().contains("xucred size") => {
        tracing::warn!("LOCAL_PEERCRED ABI mismatch; skipping peer creds: {e}");
        Ok(fallback_cred())
    }
    Err(e) => Err(e.into()),
}

Prevention

When it happens

Trigger: Calling UCred-related peer credential lookup (getsockopt LOCAL_PEERCRED) on macOS/FreeBSD where the kernel reports an xucred whose byte size differs from what tokio was compiled to expect. Most likely after a major OS upgrade that changed struct xucred.

Common situations: Major macOS/BSD upgrade that resized xucred (added/removed fields); running a tokio binary built against one SDK on a newer kernel; embedded/non-standard BSD derivative; cross-compilation toolchain ABI mismatch.

Related errors


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