rwf2/Rocket · error · rocket::serde::msgpack::Error

UnexpectedEof

UnexpectedEof

Error message

data limit exceeded

What it means

Runtime error from the MsgPack<T> FromData guard (core/lib/src/serde/msgpack.rs): the body is opened with the 'msgpack' limit (Limits::MESSAGE_PACK, default 1 MiB); if reading stops at that limit with more data remaining (into_bytes returns an incomplete Capped), the guard errors with io::ErrorKind::UnexpectedEof 'data limit exceeded' wrapped in Error::InvalidDataRead, failing the MsgPack guard (typically 413/400 depending on catcher). Same policy as the JSON guard, applied to application/msgpack bodies.

Source

Thrown at core/lib/src/serde/msgpack.rs:185

    /// ```
    #[inline(always)]
    pub fn into_inner(self) -> T {
        self.0
    }
}

impl<'r, T: Deserialize<'r>> MsgPack<T> {
    fn from_bytes(buf: &'r [u8]) -> Result<Self, Error> {
        rmp_serde::from_slice(buf).map(MsgPack)
    }

    async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Result<Self, Error> {
        let limit = req.limits().get("msgpack").unwrap_or(Limits::MESSAGE_PACK);
        let bytes = match data.open(limit).into_bytes().await {
            Ok(buf) if buf.is_complete() => buf.into_inner(),
            Ok(_) => {
                let eof = io::ErrorKind::UnexpectedEof;
                return Err(Error::InvalidDataRead(io::Error::new(eof, "data limit exceeded")));
            },
            Err(e) => return Err(Error::InvalidDataRead(e)),
        };

        Self::from_bytes(local_cache!(req, bytes))
    }
}

#[crate::async_trait]
impl<'r, T: Deserialize<'r>> FromData<'r> for MsgPack<T> {
    type Error = Error;

    async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
        match Self::from_data(req, data).await {
            Ok(value) => Outcome::Success(value),
            Err(Error::InvalidDataRead(e)) if e.kind() == io::ErrorKind::UnexpectedEof => {
                Outcome::Error((Status::PayloadTooLarge, Error::InvalidDataRead(e)))
            },

View on GitHub (pinned to 3a54d079ae)

Solutions

  1. Raise the limit: Rocket.toml [default.limits] msgpack = "10 MiB"
  2. Split large binary payloads into multiple requests or use Data<'_>/TempFile streaming instead of MsgPack<T>
  3. Add a catcher for the resulting status so clients get a clear 'payload too large' message
  4. Verify with a sized test payload (head -c 2M /dev/urandom as msgpack body)

Example fix

# before
# Rocket.toml (msgpack defaults to 1 MiB)
#[post("/ingest", data = "<batch>")]
fn ingest(batch: MsgPack<Batch>) { }

# after
# Rocket.toml
[default.limits]
msgpack = "10 MiB"

#[post("/ingest", data = "<batch>")]
fn ingest(batch: MsgPack<Batch>) { }
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check size for msgpack uploads
#[post("/ingest", data = "<data>")]
fn ingest(req: &Request<'_>, data: Data<'_>) -> Status {
    let limit: usize = 10 * 1024 * 1024;
    if let Some(len) = req.headers().get_one("Content-Length").and_then(|v| v.parse::<usize>().ok()) {
        if len > limit { return Status::PayloadTooLarge; }
    }
    Status::Ok
}

Try / catch

// server: catcher translating guard failure for msgpack clients
#[catch(413)]
fn too_large(_: &Request) -> (Status, &('static str)) {
    (Status::PayloadTooLarge, "msgpack body exceeds configured limit")
}

Prevention

When it happens

Trigger: POSTing an application/msgpack (or msgpack content-type) body larger than limits.msgpack (default 1 MiB) to a route with a MsgPack<T> guard.

Common situations: Binary-heavy APIs (embedded telemetry, sensor batches, serialized ML features) packing large blobs into one msgpack document; payload growth after launch; msgpack chosen specifically for large binary data without raising the limit.

Related errors


AI-assisted analysis of rwf2/Rocket@3a54d079ae (2026-08-16). Data as JSON: /api/errors/c2461dc2a55b2f8a. Report an issue: GitHub.