risingwavelabs/risingwave · error
failed to find handle {} when acknowledging the commit for e
Error message
failed to find handle {} when acknowledging the commit for epoch {} What it means
`ack_commit` looks up each supplied `HandleId` in `writer_handles` to acknowledge a committed epoch; this error means one of the ids was not found. As with error 1772, this signals stale or unregistered handle ids reaching the manager — the commit was for a sink writer the coordinator no longer tracks.
Source
Thrown at src/meta/src/manager/sink_coordination/coordinator_worker.rs:327
.map_err(|_| {
anyhow!(
"failed to ack aligned initial epoch {:?} for handle {}",
aligned_initial_epoch,
handle_id
)
})?;
}
Ok(())
}
fn ack_commit(
&mut self,
epoch: u64,
handle_ids: impl IntoIterator<Item = HandleId>,
) -> anyhow::Result<()> {
for handle_id in handle_ids {
let handle = self.writer_handles.get_mut(&handle_id).ok_or_else(|| {
anyhow!(
"failed to find handle {} when acknowledging the commit for epoch {}",
handle_id,
epoch
)
})?;
handle.ack_commit(epoch).map_err(|_| {
anyhow!(
"failed to acknowledge the commit for epoch {} on handle {}",
epoch,
handle_id
)
})?;
}
Ok(())
}
async fn next_request_inner(
writer_handles: &mut HashMap<HandleId, SinkWriterCoordinationHandle>,View on GitHub (pinned to 6469eb736d)
Solutions
- Filter the ids passed to `ack_commit` against currently registered handles before calling it.
- Track per-handle pending epochs so commits for removed handles are ignored rather than erroring.
- Serialize stop/parallelism-change operations against commit acknowledgment to avoid the race.
- If the sink is recovering, re-register handles before acknowledging commits.
Example fix
// before manager.ack_commit(epoch, all_pending_ids)?; // after let live: HashSet<HandleId> = manager.registered_handle_ids().collect(); manager.ack_commit(epoch, all_pending_ids.into_iter().filter(|id| live.contains(id)))?;
Defensive patterns
Strategy: validation
Validate before calling
// Drop ids for handles that no longer exist before acking let live: HashSet<_> = manager.registered_handle_ids().collect(); let ackable: Vec<_> = pending_ids.into_iter().filter(|id| live.contains(id)).collect();
Type guard
fn handle_exists(mgr: &CoordinationHandleManager, id: &HandleId) -> bool {
mgr.registered_handle_ids().contains(id)
} Try / catch
if let Err(e) = manager.ack_commit(epoch, ids) {
if e.to_string().contains("failed to find handle") {
warn!(epoch, "commit for removed handle ignored");
} else { return Err(e); }
} Prevention
- Track pending epochs per handle and drop entries when handles are removed
- Serialize stop operations against commit acks
- Ignore (don't error) commits for unregistered handles
When it happens
Trigger: A commit request was accepted from a handle that was subsequently removed (e.g. after `Stop` or during `alter_parallelisms`), and its id is later passed to `ack_commit`; or the caller passes ids from persisted metadata that do not match live registrations.
Common situations: Parallelism change concurrently dropping writers while their epochs are being committed; recovery from a snapshot where handle ids were reassigned; double commit acknowledgments after failover.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- failed to find handle {} to start
- infinite
- failed to start {:?} for handle {}
- failed to ack aligned initial epoch {:?} for handle {}
- failed to acknowledge the commit for epoch {} on handle {}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/c223be3ef11ff9d2.
Report an issue: GitHub.