{"id":"278fa18409755ad8","repo":"hyperium/hyper","slug":"io-error","errorCode":null,"errorMessage":"io error","messagePattern":"io error","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"src/ffi/io.rs","lineNumber":155,"sourceCode":"    _: *mut hyper_context<'_>,\n    _buf: *const u8,\n    _buf_len: size_t,\n) -> size_t {\n    0\n}\n\nimpl Read for hyper_io {\n    fn poll_read(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        mut buf: crate::rt::ReadBufCursor<'_>,\n    ) -> Poll<std::io::Result<()>> {\n        let buf_ptr = unsafe { buf.as_mut() }.as_mut_ptr().cast::<u8>();\n        let buf_len = buf.remaining();\n\n        match (self.read)(self.userdata, hyper_context::wrap(cx), buf_ptr, buf_len) {\n            HYPER_IO_PENDING => Poll::Pending,\n            HYPER_IO_ERROR => Poll::Ready(Err(std::io::Error::new(\n                std::io::ErrorKind::Other,\n                \"io error\",\n            ))),\n            ok => {\n                // We have to trust that the user's read callback actually\n                // filled in that many bytes... :(\n                unsafe { buf.advance(ok) };\n                Poll::Ready(Ok(()))\n            }\n        }\n    }\n}\n\nimpl Write for hyper_io {\n    fn poll_write(\n        self: Pin<&mut Self>,\n        cx: &mut Context<'_>,\n        buf: &[u8],","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/hyperium/hyper/blob/084473f728f9d07b3be5845475aa2f62ed9ff579/src/ffi/io.rs#L137-L173","documentation":"Produced inside the C FFI IO adapter (src/ffi/io.rs:155) in hyper_io::poll_read. When the user-supplied C read callback returns HYPER_IO_ERROR, hyper reports a std::io::Error of kind Other with the message 'io error' (ffi/io.rs:155-158). This is the FFI boundary: the error originates entirely in the C-side callback, not in hyper. Only reachable via the hyper C API (feature=\"ffi\").","triggerScenarios":"An application embedding hyper via the C FFI registers a read callback (hyper_io_set_read) that returns HYPER_IO_ERROR on a transport failure; poll_read (ffi/io.rs:153-158) maps that to io::Error. Common with custom transports (curl-style, another HTTP stack bridged in).","commonSituations":"The C-side transport (e.g. a socket, a TLS impl, or a bridged library) hit an error and the callback signals HYPER_IO_ERROR; mis-handling read returns (returning error for EAGAIN instead of HYPER_IO_PENDING); a transport that does not distinguish 'would block' from real failure.","solutions":["Debug the C read callback: log the underlying transport error before returning HYPER_IO_ERROR, and return HYPER_IO_PENDING for non-blocking 'would block' (EAGAIN/EWOULDBLOCK) instead of an error.","Ensure the callback fills the buffer and returns the byte count on success, 0 only for clean EOF, and HYPER_IO_ERROR solely for genuine failures.","Reproduce with the smallest C harness around your transport to confirm which condition maps to the error."],"exampleFix":"// before (C callback): returns error on EAGAIN, surfacing as 'io error'\nsize_t my_read(void* ud, hyper_context* ctx, uint8_t* buf, size_t len) {\n    ssize_t n = recv(fd, buf, len, 0);\n    if (n < 0) return HYPER_IO_ERROR;     // wrongly reports EAGAIN as fatal\n    return (size_t)n;\n}\n\n// after: distinguish would-block from real failure\nsize_t my_read(void* ud, hyper_context* ctx, uint8_t* buf, size_t len) {\n    ssize_t n = recv(fd, buf, len, 0);\n    if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return HYPER_IO_PENDING;\n    if (n < 0) return HYPER_IO_ERROR;     /* genuine failure only */\n    return (size_t)n;\n}","handlingStrategy":"validation","validationCode":"// In the C read callback, only return HYPER_IO_ERROR on genuine failures.\n// Map EAGAIN/EWOULDBLOCK to HYPER_IO_PENDING so hyper awaits readiness.\nsize_t cb_read(void* ud, hyper_context* ctx, uint8_t* buf, size_t len) {\n    ssize_t n = recv(((Fd*)ud)->fd, buf, len, 0);\n    if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return HYPER_IO_PENDING;\n    if (n < 0) { log_errno(); return HYPER_IO_ERROR; }\n    return (size_t)n;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Distinguish 'would block' (return HYPER_IO_PENDING) from real errors (HYPER_IO_ERROR) in read callbacks.","Log errno/TLS errors in the callback before returning HYPER_IO_ERROR so the cause is recoverable.","Return 0 only for clean EOF; return the byte count for partial reads."],"tags":["ffi","c","io","transport","read"],"analyzedSha":"084473f728f9d07b3be5845475aa2f62ed9ff579","analyzedAt":"2026-08-06T01:20:18.522Z","schemaVersion":2}