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

  1. Check how many shards were readable for the object (offline drives) and heal the set
  2. 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
  3. Retry the GET after bringing the drives back online
  4. 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

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


AI-assisted analysis of rustfs/rustfs@9e6e02ea09 (2026-08-16). Data as JSON: /api/errors/8d10955bfa0a5065. Report an issue: GitHub.