duplicati/duplicati · error · Exception
Failed to move block {blockkey}:{size} from volume {sourcevo
Error message
Failed to move block {blockkey}:{size} from volume {sourcevolumeid}, count: {c} What it means
Generic Exception in MoveBlockToVolumeAsync: an UPDATE setting VolumeID on Block rows matching Hash+Size+PreviousVolumeId returned != 1 affected row. Exactly one row should match; 0 means no block matches that triple (moved already, or wrong ids), >1 means duplicate blocks — both are integrity/concurrency problems.
Source
Thrown at Duplicati/Library/Main/Database/Local/LocalBackupDatabase.cs:1821
{
await using var cmd = m_connection.CreateCommand(m_rtr);
var c = await cmd.SetCommandAndParameters(@"
UPDATE ""Block""
SET ""VolumeID"" = @NewVolumeId
WHERE
""Hash"" = @Hash
AND ""Size"" = @Size
AND ""VolumeID"" = @PreviousVolumeId
")
.SetParameterValue("@NewVolumeId", targetvolumeid)
.SetParameterValue("@Hash", blockkey)
.SetParameterValue("@Size", size)
.SetParameterValue("@PreviousVolumeId", sourcevolumeid)
.ExecuteNonQueryAsync(true, token)
.ConfigureAwait(false);
if (c != 1)
throw new Exception($"Failed to move block {blockkey}:{size} from volume {sourcevolumeid}, count: {c}");
}
/// <summary>
/// Safely deletes a remote volume by checking if it has any associated blocks.
/// If it does, an exception is thrown; otherwise, the volume is removed.
/// </summary>
/// <param name="name">The name of the remote volume to delete.</param>
/// <param name="token">The cancellation token to cancel the operation.</param>
/// <returns>A task that completes when the remote volume is safely deleted.</returns>
/// <exception cref="Exception">Thrown if the volume has associated blocks.</exception>
public async Task SafeDeleteRemoteVolumeAsync(string name, CancellationToken token)
{
var volumeid = await GetRemoteVolumeIDAsync(name, token).ConfigureAwait(false);
await using var cmd = m_connection.CreateCommand(m_rtr);
var c = await cmd.SetCommandAndParameters(@"
SELECT COUNT(*)
FROM ""Block""View on GitHub (pinned to 3f348be3e3)
Solutions
- Verify the block actually still resides on sourcevolumeid before moving (avoid re-running moves).
- Serialize compaction/purge operations against the local database.
- Run database repair to deduplicate/reconcile Block rows.
- Recreate the local db from the remote store if corruption persists.
Defensive patterns
Strategy: validation
Validate before calling
// Optional: confirm the block is still on the source volume before moving: // (uses the same lookup the update performs; if absent, skip the move)
Try / catch
try { await db.MoveBlockToVolumeAsync(blockkey, size, srcVol, tgtVol, token); }
catch (Exception ex) when (ex.Message.Contains("Failed to move block"))
{ Log.Warn("Block move mismatch; block may already be relocated. Serialize jobs and run repair."); throw; } Prevention
- Don't re-run block-move/compaction operations that partially completed; repair first.
- Single-writer access to the local database.
When it happens
Trigger: Call MoveBlockToVolumeAsync(blockkey, size, sourcevolumeid, targetvolumeid) where the UPDATE matches 0 or >1 Block rows.
Common situations: Block already moved (re-running a compaction/purge), concurrent operation racing on the same block, duplicate Block rows with identical Hash+Size+VolumeID (corruption), caller passing stale/incorrect volume ids.
Related errors
- Failed to move block {key} with size {size}, result count: {
- Failed to insert block {key} with size {size}, result count:
- Failed to insert blocklist hash {bh} for blockset {blockseti
- Hash is null
- Could not find any blocks with the given hash: {h}
AI-assisted analysis of duplicati/duplicati@3f348be3e3 (2026-08-13).
Data as JSON: /api/errors/26e134d69a8a8f7c.
Report an issue: GitHub.