Received Status.source = None when server sends Status.source = Some
- Dominant language
- Rust
- Stars
- 12.5k
- Forks
- 1.3k
- Avg merge
- 4d 7h
- Merged PRs (30d)
- 24
Description
## Bug Report
### Version
tonic v0.11.0
tonic-build v0.11.0
### Platform
Linux 6.5.0-21-generic #21~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Feb 9 13:32:52 UTC 2 x86_64 x86_64 x86_64 GNU/Linux
### Description
#### Received Status.source field is None even though it is Some when sent from the server.
Situation:
GRPC server built with tonic-build encounters an error `err` and returns a `tonic::Status` with `source: err`, the client, (also built with tonic-build) receives the Status but the `source` is `None`.
I expected the `source` field of the received Status on the client's side to be populated with the same information that was sent from the client.
Below is a demo server and client cargo project as a zip file, the `server.rs` and `client.rs` files are also below for reference, along with their output.
The server simply returns a Status where the source of the status has been set.
To run the demo to reproduce, extract the zip, from within the zip;
- run `cargo run --bin server` in one terminal.
- run `cargo run --bin client` in another terminal.
See that the log message from the client states `received error: Status {..., source: None }` however the log in the server shows `sending error: Status {..., source: Some(Custom ...)}`
[tonic_status_source_bug_demo.zip](https://github.com/hyperium/tonic/files/14576264/tonic_status_source_bug_demo.zip)
#### server.rs
```rust
use std::sync::Arc;
use tonic::{transport::Server, Request, Response, Status};
pub mod error_server {
tonic::include_proto!("error_server");
}
#[derive(Debug, Default)]
pub struct ErrorServerService {}
#[tonic::async_trait]
impl error_server::error_server_server::ErrorServer for ErrorServerService {
/// Just return error
async fn error_server(
&self,
_: Request,
) -> Result, Status> {
let source_error = std::io::Error::new(std::io::ErrorKind::Other, "oh no!");
let mut status = tonic::Status::internal("error:");
status.set_source(Arc::new(source_error));
log::error!("sending error: {:?}", status);
return Err(status);
}
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let env = env_logger::Env::default()
.filter_or("LOG_LEVEL", "info")
.write_style_or("LOG_STYLE", "never");
env_logger::init_from_env(env);
let port = std::env::var("PORT").unwrap_or_else(|_| "50051".to_string());
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], port.parse()?));
let error_server = ErrorServerService::default();
log::info!("serving on {addr}");
Server::builder()
.add_service(error_server::error_server_server::ErrorServerServer::new(
error_server,
))
.serve(addr)
.await?;
Ok(())
}
```
#### client.rs
```rust
use tonic::transport::Channel;
pub mod error_server {
tonic::include_proto!("error_server");
}
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
let env = env_logger::Env::default()
.filter_or("LOG_LEVEL", "info")
.write_style_or("LOG_STYLE", "never");
env_logger::init_from_env(env);
let port = std::env::var("PORT").unwrap_or_else(|_| "50051".to_string());
let endpoint = format!("https://localhost:{port}");
// log::info!("sending requests to {host}:{port}");
let channel = Channel::from_shared(endpoint)?.connect().await?;
log::info!("channel connected");
let mut client = error_server::error_server_client::ErrorServerClient::new(channel);
let request = tonic::Request::new(error_server::Request {
text: "Hello World".to_string(),
});
match client.error_server(request).await {
Err(status) => {
// debug print the error showing that source is None.
log::error!("received error: {:?}", status);
Err(status.into())
}
Ok(response) => {
log::info!("received response: {:?}", response.into_inner());
Ok(())
}
}
}
```
#### Server output:
```
[2024-03-12T16:03:28Z INFO server] serving on 0.0.0.0:50052
[2024-03-12T16:04:20Z ERROR server] sending error: Status { code: Internal, message: "error:", source: Some(Custom { kind: Other, error: "oh no!" }) }
```
#### Client output:
```
[2024-03-12T16:04:20Z ERROR client] received error: Status { code: Internal, message: "error:", metadata: MetadataMap { headers: {"content-type": "application/grpc", "date": "Tue, 12 Mar 2024 16:04:20 GMT", "content-length": "0"} }, source: None }
Error: status: Internal, message: "error:", details: [], metadata: MetadataMap { headers: {"content-type": "application/grpc", "date": "Tue, 12 Mar 2024 16:04:20 GMT", "content-length": "0"} }
```
Contributor guide
Assessment
This issue has not been assessed yet.