risingwavelabs/risingwave · error

should have been handled

Error message

should have been handled

What it means

`next_event` matches on the received `coordinate_request::Msg` and maps each variant to an event; `StartRequest` should never appear at this point because start requests are handled earlier in `next_event` (when the handle is first registered). Hitting `unreachable!("should have been handled")` means a `StartRequest` was dispatched through the inner request path anyway — a broken invariant in the request routing logic.

Source

Thrown at src/meta/src/manager/sink_coordination/coordinator_worker.rs:416

                let event = match request {
                    coordinate_request::Msg::CommitRequest(request) => {
                        CoordinationHandleManagerEvent::CommitRequest {
                            epoch: request.epoch,
                            metadata: request.metadata.ok_or_else(|| anyhow!("empty sink metadata"))?,
                            schema_change: request.schema_change,
                        }
                    }
                    coordinate_request::Msg::AlignInitialEpochRequest(epoch) => {
                        CoordinationHandleManagerEvent::AlignInitialEpoch(epoch)
                    }
                    coordinate_request::Msg::UpdateVnodeRequest(_) => {
                        CoordinationHandleManagerEvent::UpdateVnodeBitmap
                    }
                    coordinate_request::Msg::Stop(_) => {
                        CoordinationHandleManagerEvent::Stop
                    }
                    coordinate_request::Msg::StartRequest(_) => {
                        unreachable!("should have been handled");
                    }
                };
                Ok((handle_id, event))
            }
        }
    }

    fn vnode_bitmap(&self, handle_id: HandleId) -> &Bitmap {
        self.writer_handles[&handle_id].vnode_bitmap()
    }

    fn stop_handle(&mut self, handle_id: HandleId) -> anyhow::Result<()> {
        self.writer_handles
            .remove(&handle_id)
            .expect("should exist")
            .stop()
    }

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Inspect the writer to ensure it sends `StartRequest` at most once per handle; add idempotency on the writer's retry path.
  2. Handle `StartRequest` defensively in the `match` (e.g. log and skip) instead of panicking, if duplicates are plausible.
  3. Review recent changes to `next_event`/`next_request_inner` that may have broken start-request routing.
  4. Check meta-node logs for the sink id and handle id to identify which writer re-sent the request.

Example fix

// before
coordinate_request::Msg::StartRequest(_) => {
    unreachable!("should have been handled");
}

// after
coordinate_request::Msg::StartRequest(_) => {
    warn!(handle_id, "duplicate StartRequest in request stream; ignoring");
    continue;
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure the writer sends StartRequest only once per handle
let mut start_sent = false;
fn send_start(tx: &Sender<StartRequest>, start_sent: &mut bool) -> Result<()> {
    ensure!(!*start_sent, "StartRequest already sent");
    *start_sent = true;
    tx.send(start_request)
}

Type guard

fn is_registration_path(msg: &Msg) -> bool {
    !matches!(msg, coordinate_request::Msg::StartRequest(_))
}

Try / catch

coordinate_request::Msg::StartRequest(_) => {
    warn!(handle_id, "unexpected StartRequest in request stream; ignoring instead of panicking");
    continue;
}

Prevention

When it happens

Trigger: A writer sends a second `StartRequest` after its handle is already registered and inserted, so the duplicate falls through `next_request_inner` into the `match` arm instead of being consumed by the registration path.

Common situations: Writer retry logic re-sending the start request after a timeout while the first one already registered the handle; bugs introduced when refactoring `next_event`'s select arms so start requests leak into the request stream; custom/test clients misusing the coordination protocol.

Related errors


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