9001 / 9001/copyparty

Copyparty does not load image while thumbnails are loading.

Open
#1,115 0 comments 0 reactions 1 assignee Claimed by @9001 View on GitHub
bug
Dominant language
Python
Stars
46.7k
Forks
1.9k
Avg merge
9d 2h
Merged PRs (30d)
4

Description

### Describe the bug
a description of what the bug is

When you open a folder in grid mode with high number of image files, when the thumbnails are loading then if you try to open a image it just stuck. Even if you try to navigate to another folder while thumbnails are loading sometimes that also get stuck but not always.

### To Reproduce
List of steps to reproduce the issue, or, if it's hard to reproduce, then at least a detailed explanation of what you did to run into it

Have a folder with high number of images and open it in grid mode then while thubnails are loading, try to click on one image.

### Expected behavior
a description of what you expected to happen

File should open even though thumbnails are loading.

### Screenshots
if applicable, add screenshots to help explain your problem, such as the kickass crashpage :^)

Image

Image

Image

```
1765946040.7130365

# MainThread (7ea8114a9080)
File: "", line 1, in
File: "python3.12/multiprocessing/spawn.py", line 122, in spawn_main
exitcode = _main(fd, parent_sentinel)
File: "python3.12/multiprocessing/spawn.py", line 135, in _main
return self._bootstrap(parent_sentinel)
File: "python3.12/multiprocessing/process.py", line 314, in _bootstrap
self.run()
File: "python3.12/multiprocessing/process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File: "pe-copyparty.0.1932.0/copyparty/broker_mpw.py", line 56, in __init__
Daemon(self.main, "mpw-main").join()
File: "lib/python3.12/threading.py", line 1147, in join
self._wait_for_tstate_lock()
File: "lib/python3.12/threading.py", line 1167, in _wait_for_tstate_lock
if lock.acquire(block, timeout):

# QueueFeederThread (7ea7e2ffd6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "lib/python3.12/threading.py", line 1010, in run
self._target(*self._args, **self._kwargs)
File: "python3.12/multiprocessing/queues.py", line 251, in _feed
nwait()
File: "lib/python3.12/threading.py", line 365, in wait
if not gotit:

# hsrv-pt-5 (7ea7e37fe6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 257, in periodic
time.sleep(2 if self.tp_ncli or self.ncli else 10)

# httpconn-0.16-60231 (7ea7c3fff6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 472, in thr_poolw
self.thr_client(sck, addr)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 518, in thr_client
cli.run()
File: "pe-copyparty.0.1932.0/copyparty/httpconn.py", line 209, in run
if not self.cli.run():
File: "pe-copyparty.0.1932.0/copyparty/httpcli.py", line 780, in run
return self.handle_get() and self.keepalive
File: "pe-copyparty.0.1932.0/copyparty/httpcli.py", line 1375, in handle_get
return self.tx_stack()
File: "pe-copyparty.0.1932.0/copyparty/httpcli.py", line 5451, in tx_stack
ret = html_escape(alltrace(self.args.stack_v))
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 1437, in alltrace
for fn, lno, name, line in traceback.extract_stack(stack):

# httpsrv-n5-listen-0.0.0.0-3923 (7ea7e1ffb6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 385, in thr_listen
sck, saddr = srv_sck.accept()
File: "lib/python3.12/socket.py", line 295, in accept
fd, addr = self._accept()

# mpw-main (7ea7e27fc6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/broker_mpw.py", line 73, in main
retq_id, dest, args = self.q_pend.get()
File: "python3.12/multiprocessing/queues.py", line 103, in get
res = self._recv_bytes()
File: "python3.12/multiprocessing/connection.py", line 216, in recv_bytes
buf = self._recv_bytes(maxlength)
File: "python3.12/multiprocessing/connection.py", line 430, in _recv_bytes
buf = self._recv(4)
File: "python3.12/multiprocessing/connection.py", line 395, in _recv
chunk = read(handle, remaining)

# hsrv-n5-i2da5-poolw (7ea7c17fa6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 461, in thr_poolw
task = self.tp_q.get()
File: "lib/python3.12/queue.py", line 171, in get
self.not_empty.wait()
File: "lib/python3.12/threading.py", line 355, in wait
waiter.acquire()

# hsrv-n5-i2da5-poolw (7ea7c1ffb6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 461, in thr_poolw
task = self.tp_q.get()
File: "lib/python3.12/queue.py", line 171, in get
self.not_empty.wait()
File: "lib/python3.12/threading.py", line 355, in wait
waiter.acquire()

# hsrv-n5-i2da5-poolw (7ea7c27fc6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 461, in thr_poolw
task = self.tp_q.get()
File: "lib/python3.12/queue.py", line 171, in get
self.not_empty.wait()
File: "lib/python3.12/threading.py", line 355, in wait
waiter.acquire()

# hsrv-n5-i2da5-poolw (7ea7c2ffd6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 461, in thr_poolw
task = self.tp_q.get()
File: "lib/python3.12/queue.py", line 171, in get
self.not_empty.wait()
File: "lib/python3.12/threading.py", line 355, in wait
waiter.acquire()

# hsrv-n5-i2da5-poolw (7ea7c37fe6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 461, in thr_poolw
task = self.tp_q.get()
File: "lib/python3.12/queue.py", line 171, in get
self.not_empty.wait()
File: "lib/python3.12/threading.py", line 355, in wait
waiter.acquire()

# hsrv-n5-i2da5-poolw (7ea7e0ff96c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 461, in thr_poolw
task = self.tp_q.get()
File: "lib/python3.12/queue.py", line 171, in get
self.not_empty.wait()
File: "lib/python3.12/threading.py", line 355, in wait
waiter.acquire()

# hsrv-n5-i2da5-poolw (7ea7f1eff6c0)
File: "lib/python3.12/threading.py", line 1030, in _bootstrap
self._bootstrap_inner()
File: "lib/python3.12/threading.py", line 1073, in _bootstrap_inner
self.run()
File: "pe-copyparty.0.1932.0/copyparty/util.py", line 733, in run
self.fun(*self.a, **self.ka)
File: "pe-copyparty.0.1932.0/copyparty/httpsrv.py", line 461, in thr_poolw
task = self.tp_q.get()
File: "lib/python3.12/queue.py", line 171, in get
self.not_empty.wait()
File: "lib/python3.12/threading.py", line 355, in wait
waiter.acquire()

```

### Server details (if you are using docker/podman)
remove the ones that are not relevant:
* **server OS / version:**
* **how you're running copyparty:** (docker/podman/something-else)
* **docker image:** (variant, version, and arch if you know)
* **copyparty arguments and/or config-file:**

### Server details (if you're NOT using docker/podman)
remove the ones that are not relevant:
* **server OS / version:** Ubuntu 24.04
* **what copyparty did you grab:** (sfx/exe/pip/arch/...) sfx
* **how you're running it:** (in a terminal, as a systemd-service, ...) systemd-service
* run copyparty with `--version` and grab the last 3 lines (they start with `copyparty`, `CPython`, `sqlite`) and paste them below this line:
* copyparty v1.19.22 "usernames" (2025-12-14)
CPython v3.12.3 on Linux64 24.04.1 [GCC 13.3.0]
sqlite 3.45.1*1 | jinja 3.1.6 | pyftpd 1.5.10 | tftp 0.4.0

* **copyparty arguments and/or config-file:**

### Client details
if the issue is possibly on the client-side, then mention some of the following:
* the device type and model:
* OS version:
* browser version:

### The rest of the stack
if you are connecting directly to copyparty then that's cool, otherwise please mention everything else between copyparty and the browser (reverseproxy, tunnels, etc.)

### Server log
if the issue might be server-related, include everything that appears in the copyparty log during startup, and also anything else you think might be relevant

### Additional context
any other context about the problem here

2025-12-16 23:11:23.636 dependencies found: sqlite (sessions and file/media indexing)
2025-12-16 23:11:23.636 dependencies found: pillow (image thumbnails (plenty fast))
2025-12-16 23:11:23.636 dependencies found: vips (image thumbnails (faster, eats more ram))
2025-12-16 23:11:23.636 dependencies found: pillow-webp (create thumbnails as webp files)
2025-12-16 23:11:23.636 dependencies found: ffmpeg (transcode audio, create spectrograms, video thumbnails, good-but-slow image thumbnails)
2025-12-16 23:11:23.636 dependencies found: ffprobe (transcode audio, create spectrograms, video thumbnails, read audio/media tags)
2025-12-16 23:11:23.636 dependencies found: mutagen (read audio tags (ffprobe is better but slower))
2025-12-16 23:11:23.636 dependencies found: argon2 (secure password hashing (advanced users only))
2025-12-16 23:11:23.636 dependencies found: pyzmq (send zeromq messages from event-hooks)
2025-12-16 23:11:23.636 dependencies found: pillow-heif (read .heif images with pillow (rarely useful))
2025-12-16 23:11:23.636 dependencies found: pillow-avif (read .avif images with pillow (rarely useful))
2025-12-16 23:11:23.636 dependencies found: rawpy (read RAW images)

Contributor guide

Open the contributing guide

Research direction

The issue involves the thumbnail generation and request handling in the web interface. Start by examining the grid mode UI code in the frontend (likely JavaScript) and the thumbnail generation/queueing in the backend, particularly in copyparty/httpsrv.py and copyparty/httpcli.py. The stack trace shows threads waiting on queues; look at the multiprocessing broker in copyparty/broker_mpw.py. Reproduce the bug by loading a folder with many images and observing the request flow. The fix likely involves ensuring image opening requests are prioritized or not blocked by thumbnail generation.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.