risingwavelabs/risingwave · error · anyhow::Error
No writer to close
Error message
No writer to close
What it means
During a checkpoint barrier, inner.close() returns the writer's rolling data-file writer. None means the inner writer had no active writer to flush/close, so RisingWave cannot produce commit metadata for this epoch and fails with this anyhow error. It indicates the writer produced no data-file writer for a checkpointed epoch.
Solutions
- Confirm barrier(is_checkpoint=true) is only called once per epoch
- Check that write_batch (or partitioning logic) created the data-file writer before the checkpoint
- For intentionally empty commits, allow None data files instead of erroring, if that matches expected semantics
Defensive patterns
Strategy: try-catch
Validate before calling
// ensure the epoch produced a writer before checkpointing
if inner.current_writer().is_none() { return Ok(None); } Try / catch
match inner.close().await { Ok(Some(files)) => Some(inner.generate_commit_metadata(files)?), Ok(None) => None, Err(e) => return Err(e.into()) } Prevention
- Call barrier(is_checkpoint=true) exactly once per epoch
- Write data (or explicitly handle empty epochs) before checkpointing
- Log epoch state at checkpoint time to catch double-close bugs
When it happens
Trigger: barrier(is_checkpoint=true) invoked when the IcebergSinkWriterInner has no current data-file writer — e.g. an epoch that received no rows was still expected to commit, or the inner writer was already closed/consumed by a previous checkpoint.
Common situations: Checkpointing an empty epoch after a rescale or restart; double barrier handling; writer reuse bugs after a failed commit.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- iceberg sink: partition evolution not supported; expect…
- iceberg sink: schema evolution not supported; expect schema…
- IcebergSinkWriter should be initialized before barrier
- Invalid order key item
- Invalid order key item
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/b7d7eb4b37d9107d.
Report an issue: GitHub.
Appendix: source
Thrown at src/connector/src/sink/iceberg/writer.rs:966
inner.write_batch(chunk).await
}
/// Receive a barrier and mark the end of current epoch. When `is_checkpoint` is true, the sink
/// writer should commit the current epoch.
async fn barrier(&mut self, is_checkpoint: bool) -> Result<Option<SinkMetadata>> {
let Self::Initialized(inner) = self else {
unreachable!("IcebergSinkWriter should be initialized before barrier");
};
// Skip it if not checkpoint
if !is_checkpoint {
return Ok(None);
}
let data_files = inner
.close()
.await?
.ok_or_else(|| anyhow!("No writer to close"))?;
let res = inner.generate_commit_metadata(data_files)?;
Ok(Some(res))
}
}
/// Maximum size for column statistics (min/max values) in bytes.
/// Column statistics larger than this will be truncated to avoid metadata bloat.
/// This is especially important for large fields like JSONB, TEXT, BINARY, etc.
///
/// Fix for large column statistics in `DataFile` metadata that can cause OOM errors.
/// We truncate at the `DataFile` level (before serialization) by directly modifying
/// the public `lower_bounds` and `upper_bounds` fields.
///
/// This prevents metadata from ballooning to gigabytes when dealing with large
/// JSONB, TEXT, or BINARY fields, while still preserving statistics for small fields
/// that benefit from query optimization.
const MAX_COLUMN_STAT_SIZE: usize = 10240; // 10KB
View on GitHub (pinned to 6469eb736d)