mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2026-03-02 22:57:32 -05:00
"Last seen complete" column lies #17354
Labels
No labels
Accessibility
AppImage
Bounty
Build system
CI
Can't reproduce
Code cleanup
Confirmed bug
Confirmed bug
Core
Crash
Data loss
Discussion
Docker
Documentation
Duplicate
Feature
Feature request
Feature request
Feature request
Filters
Flatpak
GUI
Has workaround
I2P
Invalid
Libtorrent
Look and feel
Meta
NSIS
Network
Not an issue
OS: *BSD
OS: Linux
OS: Windows
OS: macOS
PPA
Performance
Project management
Proxy/VPN
Qt bugs
Qt6 compat
RSS
Search engine
Security
Temp folder
Themes
Translations
Triggers
Waiting diagnosis
Waiting info
Waiting upstream
Waiting web implementation
Watched folders
WebAPI
WebUI
autoCloseOldIssue
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/qBittorrent#17354
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @cheater on GitHub (Dec 11, 2025).
qBittorrent & operating system versions
5.1.4 Win11 x64
What is the problem?
I just added this torrent, it has only one leech at 45%, but "last seen complete" column is showing a date 1 minute ago (when I added the torrent). In this situation it should be empty.
Steps to reproduce
No response
Additional context
No response
@schnurlos commented on GitHub (Dec 13, 2025):
The one "last seen" could be an IP you have banned or got blocked by qbittorrent.
@cheater commented on GitHub (Dec 13, 2025):
"or got blocked by qbittorrent" - what does that mean?
I've never banned any peers
@thalieht commented on GitHub (Dec 13, 2025):
You can't know that.
@LookForward2 commented on GitHub (Jan 4, 2026):
In a DHT network there are torrent clients that were modified (patched) to announce allegedly they are seeds but in fact they are not. I've seen lots of such fake seeds have IPs from one IP sub-network. Some company seems doing it on purpose
@peterdrier commented on GitHub (Jan 13, 2026):
I watched this for a good half hour once and I think I figured it out.
When new connections come in / are created, during their initial handshake, they seem to display 100% done for a split second before they actually show how much they really have. It's enough to make the last seen complete reset to now, but the remote site doesn't actually have the complete file (or immediately leaves..)
My gut says it's either a default value logic bug. i.e. defaults to 100% to avoid a divide by 0 type error at init. Or possibly a rogue agent out there connecting, lying about the completeness, and then immediately disconnecting.
If the latter, perhaps a check in the "last seen" update logic, to only allow updates to now() when the connection is providing file bytes? i.e. Only update the last seen when a remote client has started downloading to me, and they're at 100%. As it's purely an informational field, being overly aggressive about not updating it to now shouldn't harm anything.
@peterdrier commented on GitHub (Jan 13, 2026):
Seems this is actually a bug in libtorrent, specifically peer_connection.cpp:
The original, flawed logic in the is_seed() function was:
1 return m_num_pieces == m_have_piece.size()
2 && m_num_pieces > 0 && t && t->valid_metadata();
Here's why this was incorrect:
the torrent. It does not tell you how many of those pieces the peer actually has.
During the initial handshake, the m_have_piece bitfield might be initialized to its full size, but with all bits set
to 0 (indicating the peer has no pieces yet). At that moment, m_num_pieces == m_have_piece.size() would evaluate to
true (e.g., 1000 == 1000), even though the peer had none of the actual pieces. This would incorrectly identify the
peer as a seed.
The fix, using m_have_piece.all_set(), is much more accurate:
1 return m_have_piece.all_set()
2 && m_num_pieces > 0 && t && t->valid_metadata();
m_have_piece.all_set() checks if every single bit in the m_have_piece bitfield is set to 1. A bit being 1 signifies
that the peer has that corresponding piece. Therefore, m_have_piece.all_set() only returns true if and only if the
peer has all the pieces of the torrent.
I'll see if I can get a patch going on the libtorrent side...
@cheater commented on GitHub (Jan 15, 2026):
thank you for looking into this
On Tue, Jan 13, 2026 at 5:58 PM Peter Drier @.***>
wrote:
@peterdrier commented on GitHub (Jan 28, 2026):
Turns out it's a straight up malicious actor coming from a russian ip address block, who seems to be scanning the DHT network, and pinging various torrents every few minutes. Not sure if this is a way of scraping what's going on downloads wise, an intentionally hack of the last seen complete field, or what.
The code above wasn't actually a fix, but have found another change for libtorrent (hopefully makes the 2.0 rc) which will improve the situation.
@cheater commented on GitHub (Jan 29, 2026):
thanks for the update.
there are a few options that come to my mind on how to alleviate this:
what did the libtorrent change do?
@cheater commented on GitHub (Jan 29, 2026):
you previously thought this was a bug in libtorrent, but now you believe it's a malicious peer. is what made you believe it was a bug in libtorrent still valid after the discovery of the malicious peer? and do you still believe there is a bug?
@peterdrier commented on GitHub (Feb 1, 2026):
bug was believed to be a race condition at connection. That turned out not to be the case, and instead was a malicious actor, basically spamming the DHT network with 100% availability pings (possibly while scanning the network itself?)
bug has a specific definition, which this isn't. Conceptually though, this is undesired behavior. So changing the definition of how last_seen_complete functions internally is a way forward, excluding the behavior of the malicious behavior. the maintainer of libtorrent agreed, and given enough cycles the change will get into a release.
@cheater commented on GitHub (Feb 1, 2026):
amazing, thank you for elaborating. I really appreciate your work.
@cheater commented on GitHub (Feb 21, 2026):
I wonder if this is related? https://www.youtube.com/watch?v=VZ-7t1fN7eI