{"record":{"id":"4bce1bdbaa2630df","repo":"duplicati/duplicati","slug":"refusing-to-remove-remote-volumes-detected-nonat","errorCode":null,"errorMessage":"Refusing to remove remote volumes, detected {nonAttachedFilesPre} file(s) in FilesetEntry without corresponding FileLookup entry","messagePattern":"Refusing to remove remote volumes, detected (.+?) file\\(s\\) in FilesetEntry without corresponding FileLookup entry","errorType":"exception","errorClass":"ConstraintException","httpStatus":null,"severity":"error","filePath":"Duplicati/Library/Main/Database/Local/LocalDatabase.cs","lineNumber":1035,"sourceCode":"        /// <returns>A task that completes when the remote volumes have been removed.</returns>\n        public async Task RemoveRemoteVolumesAsync(IEnumerable<string> names, CancellationToken token)\n        {\n            if (names == null || !names.Any()) return;\n\n            await using var deletecmd = m_connection.CreateCommand(m_rtr);\n\n            var nonAttachedFilesPre = await deletecmd.ExecuteScalarInt64Async(@\"\n                SELECT COUNT(*)\n                FROM \"\"FilesetEntry\"\"\n                WHERE \"\"FileID\"\" NOT IN (\n                    SELECT \"\"ID\"\"\n                    FROM \"\"FileLookup\"\"\n                )\n            \", token)\n                .ConfigureAwait(false);\n\n            if (nonAttachedFilesPre > 0)\n                throw new ConstraintException($\"Refusing to remove remote volumes, detected {nonAttachedFilesPre} file(s) in FilesetEntry without corresponding FileLookup entry\");\n\n\n            string temptransguid = Library.Utility.Utility.GetHexGuid();\n            var volidstable = $\"DelVolSetIds-{temptransguid}\";\n            var blocksetidstable = $\"DelBlockSetIds-{temptransguid}\";\n            var filesetidstable = $\"DelFilesetIds-{temptransguid}\";\n\n            // Create and fill a temp table with the volids to delete. We avoid using too many parameters that way.\n            await deletecmd.ExecuteNonQueryAsync($@\"\n                CREATE TEMP TABLE \"\"{volidstable}\"\" (\n                    \"\"ID\"\" INTEGER PRIMARY KEY\n                )\n            \", token)\n                .ConfigureAwait(false);\n\n            await using var tmptable = await TemporaryDbValueList.CreateAsync(this, names, token)\n                .ConfigureAwait(false);\n","sourceCodeStart":1017,"sourceCodeEnd":1053,"githubUrl":"https://github.com/duplicati/duplicati/blob/3f348be3e33f5d72d414e3ad55839c2ba34dda67/Duplicati/Library/Main/Database/Local/LocalDatabase.cs#L1017-L1053","documentation":"Thrown by RemoveRemoteVolumesAsync as a pre-condition guard: it counts FilesetEntry rows whose FileID has no matching ID in FileLookup, and refuses to proceed if any exist. Removing volumes cascades block/blockset deletions, so orphaned FilesetEntry rows would compound corruption; the method aborts before mutating. A non-zero count indicates referential-integrity breakage that must be fixed first.","triggerScenarios":"Calling RemoveRemoteVolumeAsync / RemoveRemoteVolumesAsync on a database where FilesetEntry references FileIDs absent from FileLookup. This precedes the volume-deletion logic (temp tables, blockset cleanup).","commonSituations":"Database corruption from a crash mid-backup. Interrupted prior volume removal that left dangling FilesetEntry rows. Manual edits or partial restore of the database. Schema/invariant violation surfaced during purge.","solutions":["Run the Duplicati repair command to rebuild FileLookup/FilesetEntry integrity before purging volumes.","If repair cannot fix it, recreate the local database from the remote backend.","Investigate the count: SELECT COUNT(*) FROM \"FilesetEntry\" WHERE \"FileID\" NOT IN (SELECT \"ID\" FROM \"FileLookup\").","Restore the local database from a known-good copy and retry the purge."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var orphaned = await cmd.ExecuteScalarInt64Async(\"SELECT COUNT(*) FROM \\\"FilesetEntry\\\" WHERE \\\"FileID\\\" NOT IN (SELECT \\\"ID\\\" FROM \\\"FileLookup\\\")\", token);\nif (orphaned > 0) /* run repair before removing volumes */","typeGuard":null,"tryCatchPattern":"try { await db.RemoveRemoteVolumeAsync(name, token); }\ncatch (ConstraintException ex) when (ex.Message.Contains(\"Refusing to remove remote volumes\")) { /* repair first, then retry */ }","preventionTips":["Run VerifyConsistency before purging volumes.","Never interrupt a backup/purge mid-way; if you do, repair before further operations.","Keep the database on reliable storage."],"tags":["data-integrity","corruption","fileset","constraint","csharp"],"backgroundTag":null,"analyzedSha":"3f348be3e33f5d72d414e3ad55839c2ba34dda67","analyzedAt":"2026-08-13T16:48:27.008Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}