{"record":{"id":"26e134d69a8a8f7c","repo":"duplicati/duplicati","slug":"failed-to-move-block-blockkey-size-from-volume","errorCode":null,"errorMessage":"Failed to move block {blockkey}:{size} from volume {sourcevolumeid}, count: {c}","messagePattern":"Failed to move block (.+?):(.+?) from volume (.+?), count: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Duplicati/Library/Main/Database/Local/LocalBackupDatabase.cs","lineNumber":1821,"sourceCode":"        {\n            await using var cmd = m_connection.CreateCommand(m_rtr);\n            var c = await cmd.SetCommandAndParameters(@\"\n                    UPDATE \"\"Block\"\"\n                    SET \"\"VolumeID\"\" = @NewVolumeId\n                    WHERE\n                        \"\"Hash\"\" = @Hash\n                        AND \"\"Size\"\" = @Size\n                        AND \"\"VolumeID\"\" = @PreviousVolumeId\n                    \")\n                .SetParameterValue(\"@NewVolumeId\", targetvolumeid)\n                .SetParameterValue(\"@Hash\", blockkey)\n                .SetParameterValue(\"@Size\", size)\n                .SetParameterValue(\"@PreviousVolumeId\", sourcevolumeid)\n                .ExecuteNonQueryAsync(true, token)\n                .ConfigureAwait(false);\n\n            if (c != 1)\n                throw new Exception($\"Failed to move block {blockkey}:{size} from volume {sourcevolumeid}, count: {c}\");\n        }\n\n        /// <summary>\n        /// Safely deletes a remote volume by checking if it has any associated blocks.\n        /// If it does, an exception is thrown; otherwise, the volume is removed.\n        /// </summary>\n        /// <param name=\"name\">The name of the remote volume to delete.</param>\n        /// <param name=\"token\">The cancellation token to cancel the operation.</param>\n        /// <returns>A task that completes when the remote volume is safely deleted.</returns>\n        /// <exception cref=\"Exception\">Thrown if the volume has associated blocks.</exception>\n        public async Task SafeDeleteRemoteVolumeAsync(string name, CancellationToken token)\n        {\n            var volumeid = await GetRemoteVolumeIDAsync(name, token).ConfigureAwait(false);\n\n            await using var cmd = m_connection.CreateCommand(m_rtr);\n            var c = await cmd.SetCommandAndParameters(@\"\n                    SELECT COUNT(*)\n                    FROM \"\"Block\"\"","sourceCodeStart":1803,"sourceCodeEnd":1839,"githubUrl":"https://github.com/duplicati/duplicati/blob/3f348be3e33f5d72d414e3ad55839c2ba34dda67/Duplicati/Library/Main/Database/Local/LocalBackupDatabase.cs#L1803-L1839","documentation":"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.","triggerScenarios":"Call MoveBlockToVolumeAsync(blockkey, size, sourcevolumeid, targetvolumeid) where the UPDATE matches 0 or >1 Block rows.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Optional: confirm the block is still on the source volume before moving:\n// (uses the same lookup the update performs; if absent, skip the move)","typeGuard":null,"tryCatchPattern":"try { await db.MoveBlockToVolumeAsync(blockkey, size, srcVol, tgtVol, token); }\ncatch (Exception ex) when (ex.Message.Contains(\"Failed to move block\"))\n{ Log.Warn(\"Block move mismatch; block may already be relocated. Serialize jobs and run repair.\"); throw; }","preventionTips":["Don't re-run block-move/compaction operations that partially completed; repair first.","Single-writer access to the local database."],"tags":["database","sqlite","data-integrity","concurrency","backup"],"backgroundTag":null,"analyzedSha":"3f348be3e33f5d72d414e3ad55839c2ba34dda67","analyzedAt":"2026-08-13T16:48:27.008Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}