Fix 'Delete File Too' silently failing when file path cannot be resolved

When the DB stored a path the resolver couldn't map to a local file
(common with Navidrome virtual paths or Docker path mismatches), file
deletion was silently skipped — the DB record was removed but the file
stayed on disk with no indication to the user.

Now logs the resolution failure with the stored path, returns a
file_error in the API response, and the frontend shows a warning toast
explaining the file wasn't deleted plus a second toast with the specific
reason (e.g. Navidrome 'Report Real Path' instructions).
This commit is contained in:
Broque Thomas 2026-04-16 08:43:16 -07:00
parent 4dab3de2d6
commit 1c8a25cff9
2 changed files with 20 additions and 3 deletions

View file

@ -14621,6 +14621,7 @@ def library_delete_track(track_id):
track_info = cursor.fetchone()
# Delete file from disk if requested
file_error = None
if delete_file and track_info and track_info['file_path']:
resolved = _resolve_library_file_path(track_info['file_path'])
if resolved and os.path.exists(resolved):
@ -14630,6 +14631,10 @@ def library_delete_track(track_id):
logger.info(f"Deleted file from disk: {resolved}")
except Exception as e:
logger.warning(f"Failed to delete file: {e}")
file_error = str(e)
else:
logger.warning(f"Could not resolve file path for deletion: {track_info['file_path']} (resolved={resolved})")
file_error = _get_file_not_found_error(track_info['file_path'])
# Add to blacklist if requested
if add_blacklist and track_info and track_info['file_path']:
@ -14651,7 +14656,10 @@ def library_delete_track(track_id):
if cursor.rowcount == 0:
return jsonify({"success": False, "error": "Track not found"}), 404
return jsonify({"success": True, "deleted_count": cursor.rowcount, "file_deleted": file_deleted, "blacklisted": blacklisted})
result = {"success": True, "deleted_count": cursor.rowcount, "file_deleted": file_deleted, "blacklisted": blacklisted}
if delete_file and not file_deleted and file_error:
result["file_error"] = file_error
return jsonify(result)
except Exception as e:
print(f"Error deleting track {track_id}: {e}")
import traceback

View file

@ -46295,9 +46295,18 @@ async function deleteLibraryTrack(trackId, albumId) {
if (!result.success) throw new Error(result.error);
let msg = 'Track removed from library';
if (result.file_deleted) msg = 'Track deleted from library and disk';
let toastType = 'success';
if (result.file_deleted) {
msg = 'Track deleted from library and disk';
} else if (result.file_error) {
msg = 'Track removed from library but file could not be deleted';
toastType = 'warning';
}
if (result.blacklisted) msg += ' (source blacklisted)';
showToast(msg, 'success');
showToast(msg, toastType);
if (result.file_error) {
showToast(result.file_error, 'error', 8000);
}
if (artistDetailPageState.enhancedData) {
const albums = artistDetailPageState.enhancedData.albums || [];