rustfs/rustfs · error · io::Error
Missing data block
Error message
Missing data block
What it means
Emit-stage guard in write_data_blocks: within the first data_blocks slots of the decoded stripe, at least one block is None. The up-front count check passed, but a required data block is missing — reconstruction should have filled every data slot before the write stage, so reaching this guard means stripe assembly and the write stage disagree. Fails with UnexpectedEof (ShortRead reason).
Source
Thrown at crates/ecstore/src/erasure/coding/decode.rs:1461
return Err(io::Error::new(ErrorKind::UnexpectedEof, "Not enough data blocks to write"));
}
let mut total_written = 0;
let mut write_left = length;
for block_op in &en_blocks[..data_blocks] {
let Some(block) = block_op else {
let reason = GetObjectFailureReason::ShortRead;
error!(
data_blocks,
offset,
length,
stage = GET_STAGE_EMIT,
reason = reason.as_str(),
"Write data blocks found a missing data shard"
);
record_get_object_pipeline_failure(GET_STAGE_EMIT, reason);
return Err(io::Error::new(ErrorKind::UnexpectedEof, "Missing data block"));
};
if offset >= block.len() {
offset -= block.len();
continue;
}
let block_slice = &block[offset..];
offset = 0;
let write_len = write_left.min(block_slice.len());
let write_stage_start = get_stage_timer_if_enabled(rustfs_io_metrics::get_stage_metrics_enabled());
if let Err(e) = writer.write_all(&block_slice[..write_len]).await {
if let Some(write_stage_start) = write_stage_start {
rustfs_io_metrics::record_get_object_duplex_backpressure_duration(write_stage_start.elapsed().as_secs_f64());
}
let reason = classify_io_error(&e);
if reason == GetObjectFailureReason::DownstreamClosed {View on GitHub (pinned to 9e6e02ea09)
Solutions
- Check how many shards were readable for the object (offline drives) and heal the set
- Capture the parallel reader's per-shard outcomes for the failing GET from metrics/debug logs; if quorum logic allowed a short set through, report it
- Retry the GET after bringing the drives back online
- If it reproduces with all shards healthy, preserve the object and open an issue with the stripe logs
Defensive patterns
Strategy: fallback
Type guard
fn is_missing_block(err: &std::io::Error) -> bool {
err.kind() == std::io::ErrorKind::UnexpectedEof
&& err.to_string().contains("Missing data block")
} Try / catch
match result {
Err(e) if is_missing_block(&e) => {
// stripe assembly inconsistent: retry once after refresh; then heal/fallback
}
r => r,
} Prevention
- Keep enough drives online that decode quorum never reaches the write stage short
- Run heal after replacing drives
- Preserve stripe logs when this fires — it indicates an internal inconsistency worth reporting
When it happens
Trigger: Shard loss beyond what the stripe's reconstruction could fill while the write stage was still invoked; corrupted block bookkeeping between decode and write; a defect in the parallel reader's completion tracking.
Common situations: Degraded pools with more offline shards than expected; races between shard reads and reader retirement; version skew inside the decode pipeline.
Related errors
- data block count exceeds available shards
- Not enough data blocks to write
- UnexpectedEof
- missing shard {index} after RustFS codec reconstruction
- inconsistent read source shards
AI-assisted analysis of rustfs/rustfs@9e6e02ea09 (2026-08-16).
Data as JSON: /api/errors/8d10955bfa0a5065.
Report an issue: GitHub.