spacedriveapp/spacedrive · error · anyhow::Error
Expected TransferFinalAck, got different message type
Error message
Expected TransferFinalAck, got different message type
What it means
The acknowledgment decoded successfully but was not TransferFinalAck - most commonly the peer sent TransferError instead, meaning its post-receive verification (size or checksum) failed. A late control message arriving before the ack produces the same error. The job fails after the entire file was already transmitted.
Source
Thrown at core/src/ops/files/copy/strategy.rs:1307
let mut len_buf = [0u8; 4];
recv_stream.read_exact(&mut len_buf).await?;
let msg_len = u32::from_be_bytes(len_buf) as usize;
let mut msg_buf = vec![0u8; msg_len];
recv_stream.read_exact(&mut msg_buf).await?;
let ack_message: crate::service::network::protocol::file_transfer::FileTransferMessage =
rmp_serde::from_slice(&msg_buf)?;
match ack_message {
crate::service::network::protocol::file_transfer::FileTransferMessage::TransferFinalAck { transfer_id: ack_id } => {
if ack_id != transfer_id {
return Err(anyhow::anyhow!("Received ack for wrong transfer: expected {}, got {}", transfer_id, ack_id));
}
ctx.log("Received TransferFinalAck from receiver - transfer confirmed!".to_string());
}
_ => {
return Err(anyhow::anyhow!("Expected TransferFinalAck, got different message type"));
}
}
// Only mark completed after receiver confirms to detect network failures.
file_transfer_protocol.update_session_state(
&transfer_id,
crate::service::network::protocol::file_transfer::TransferState::Completed,
)?;
ctx.log(format!(
"File streaming completed and acknowledged: {} chunks, {} bytes sent to device {}",
chunk_index, bytes_transferred, destination_device_id
));
// Signal file completion to aggregator
if let Some(callback) = progress_callback {
callback(bytes_transferred, u64::MAX);
}View on GitHub (pinned to 6dfeccf211)
Solutions
- If the message is a TransferError, inspect its contents for the receiver-side failure (usually checksum mismatch) and check disk health on the receiver
- Check free disk space on the receiving device
- Retry the transfer after addressing the receiver-side cause
- Align sd-core versions on both devices
Defensive patterns
Strategy: try-catch
Try / catch
match ack_message {
FileTransferMessage::TransferFinalAck { transfer_id } if transfer_id == expected => { /* confirmed */ }
FileTransferMessage::TransferError { message, .. } => {
// Receiver verified and rejected; retrying blindly repeats the failure.
anyhow::bail!("Receiver rejected transfer: {}", message);
}
other => anyhow::bail!("Unexpected final message: {:?}", other),
} Prevention
- Verify receiver disk space and health before large transfers
- Keep verification logic versions aligned across devices
- Log the full unexpected message variant for diagnosis
When it happens
Trigger: Receiver-side checksum or size verification fails after all chunks arrive, so it answers with TransferError; protocol version differences emit a different final message; an unexpected control message interleaves before the ack.
Common situations: Receiver disk truncating writes, receiver running different verification logic after an upgrade, memory pressure causing partial writes on the receiver.
Related errors
- Failed to finish stream: {}
- Transfer error: {}
- Transfer interrupted: received {} of {} bytes before connect
- Failed to open stream: {}
- Failed to write message length: {}
AI-assisted analysis of spacedriveapp/spacedrive@6dfeccf211 (2026-08-16).
Data as JSON: /api/errors/929e67c8b133c952.
Report an issue: GitHub.