risingwavelabs/risingwave · error · RpcError

get empty response from first request

Error message

get empty response from first request

What it means

BidiStreamHandle::initialize expects the server to answer the first request with an immediate first response, but the response stream ended before yielding anything. The stream produced None on the first poll, converted to this anyhow error.

Solutions

  1. Retry initialize; if persistent, check server logs for why the streaming handler returned without a response.
  2. Verify client and server protobuf definitions/versions match so the handler does not bail on the first message.
  3. Confirm the service endpoint is the correct one (not a proxy that terminates streams).

Example fix

// before
let first_response = response_stream.next().await.ok_or_else(|| anyhow!("get empty response from first request"))??;
// after (caller)
let first_response = match handle.response_stream.next_response().await {
    Ok(rsp) => rsp,
    Err(e) => return Err(anyhow!("stream closed before first response: {e}")),
};
Defensive patterns

Strategy: retry

Try / catch

match BidiStreamHandle::initialize(&client, first_req).await {
    Err(e) if e.to_string().contains("get empty response from first request") => {
        // server closed stream without answering: retry after delay, then fail with server-log hint
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling initialize against a server whose streaming method returns an empty stream: the service accepted the request but terminated without responding (immediate error/cancellation).

Common situations: Server-side handler rejected the first request and closed the stream without an explicit error frame; incompatible protocol versions; service crash between stream creation and first response.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/490b9122cddc93b7. Report an issue: GitHub.

Appendix: source

Thrown at src/rpc_client/src/lib.rs:291

        R: Into<REQ>,
    >(
        first_request: R,
        init_stream_fn: F,
    ) -> Result<(Self, RSP)> {
        let (request_sender, request_receiver) = channel(DEFAULT_BUFFER_SIZE);

        // Send initial request in case of the blocking receive call from creating streaming request
        request_sender
            .send(first_request.into())
            .await
            .map_err(|_err| anyhow!("unable to send first request of {}", type_name::<REQ>()))?;

        let mut response_stream = init_stream_fn(request_receiver).await?;

        let first_response = response_stream
            .next()
            .await
            .ok_or_else(|| anyhow!("get empty response from first request"))??;

        Ok((
            Self {
                request_sender: BidiStreamSender { tx: request_sender },
                response_stream: BidiStreamReceiver {
                    stream: response_stream.boxed().peekable(),
                },
            },
            first_response,
        ))
    }

    pub async fn next_response(&mut self) -> Result<RSP> {
        self.response_stream.next_response().await
    }

    pub async fn send_request(&mut self, request: REQ) -> Result<()> {
        match await_future_with_monitor_error_stream(

View on GitHub (pinned to 6469eb736d)