[Bug]: 'Scan Duplicate Files' Crashes App Nearly Immediately #111

Closed
opened 2026-06-20 06:30:18 +00:00 by ValleyGeek · 8 comments
Owner

App version

0.1.36 Beta

Platform

Windows

Steps to reproduce

  1. Open a directory
  2. The the 'Scan Duplicate Files' operation

Expected behavior

Duplicate file scan runs

Actual behavior

Program crashes and closes before scan starts displaying a file count for progress

Additional context

No present in v0.1.35

### App version 0.1.36 Beta ### Platform Windows ### Steps to reproduce 1. Open a directory 2. The the 'Scan Duplicate Files' operation ### Expected behavior Duplicate file scan runs ### Actual behavior Program crashes and closes before scan starts displaying a file count for progress ### Additional context No present in v0.1.35
ValleyGeek changed title from [Bug]: Scan for Duplicate Files Crashes to [Bug]: 'Scan Duplicate Files' Crashes App Nearly Immediately 2026-06-20 06:31:48 +00:00
Member

Fixed on branch 0.1.38/issue-111-dupe-scan-crash (queued for PR to main, not yet opened).

Root cause: _start_dupe_scan() and its progress/finished/error signal handlers in main_window.py had no exception handling of their own. Any exception raised while starting the scan, or while the main thread handled a queued signal from the background DupeWorker, propagated straight out of a Qt slot instead of being caught. On the Windows build (--windows-console-mode=disable, no console) there's nowhere visible for that traceback to land, so the app simply appears to crash and close.

Fix:

  • Wrapped the synchronous scan-start path and the progress/finished/error handlers in try/except, routing failures through a new _fail_dupe_scan() helper that resets scan state and shows a "Duplicate Scan Error" dialog instead of letting the exception escape.
  • Fixed a related logging bug: packaged-build detection only checked sys.frozen, which Nuitka doesn't always set, so the real packaged app fell through to the dev logging path and ended up with no usable log output at all (a stdout handler bound to None on Windows, and no file handler). Packaged builds now get a durable log file under the user config directory, so a future crash like this one leaves a trace to diagnose from.

Added regression tests (tests/test_dupe_scan_crash_guard.py) that inject failures into the start path, the progress handler, and the finished handler, and assert the app surfaces an error dialog instead of raising.

Closing — direction was clear from the report and the fix is implemented and tested. Reopen if it still reproduces once you've had a chance to try a build from this branch.

Fixed on branch `0.1.38/issue-111-dupe-scan-crash` (queued for PR to `main`, not yet opened). Root cause: `_start_dupe_scan()` and its progress/finished/error signal handlers in `main_window.py` had no exception handling of their own. Any exception raised while starting the scan, or while the main thread handled a queued signal from the background `DupeWorker`, propagated straight out of a Qt slot instead of being caught. On the Windows build (`--windows-console-mode=disable`, no console) there's nowhere visible for that traceback to land, so the app simply appears to crash and close. Fix: - Wrapped the synchronous scan-start path and the progress/finished/error handlers in try/except, routing failures through a new `_fail_dupe_scan()` helper that resets scan state and shows a "Duplicate Scan Error" dialog instead of letting the exception escape. - Fixed a related logging bug: packaged-build detection only checked `sys.frozen`, which Nuitka doesn't always set, so the real packaged app fell through to the dev logging path and ended up with no usable log output at all (a stdout handler bound to `None` on Windows, and no file handler). Packaged builds now get a durable log file under the user config directory, so a future crash like this one leaves a trace to diagnose from. Added regression tests (`tests/test_dupe_scan_crash_guard.py`) that inject failures into the start path, the progress handler, and the finished handler, and assert the app surfaces an error dialog instead of raising. Closing — direction was clear from the report and the fix is implemented and tested. Reopen if it still reproduces once you've had a chance to try a build from this branch.
Author
Owner

Application still crashes when attempting scan, no perceivable change in behavior. I was unable to locate the log file in the user directory.

Application still crashes when attempting scan, no perceivable change in behavior. I was unable to locate the log file in the user directory.
Member

Thanks for testing the previous fix and reporting back — sorry that one didn't land. Continued on branch 0.1.47/issue-111-86-64-89-feedback-fixes (chained after the dev work in progress).

I want to be upfront: I could not reproduce this crash from this (Linux, source-run) development environment, and I don't have access to a Windows machine to test the packaged build directly. I diffed the actual application code between the v0.1.35 and v0.1.36 tags and found nothing touching the dupe-scan path (_start_dupe_scan, DupeWorker, hashing) — so I don't think this was a code regression introduced between those two versions; it looks like a pre-existing issue that happened to surface around when you upgraded. Given the prior fix's try/except wrapping apparently never triggered (no dialog appeared, matching your report of "no perceivable change"), the most likely explanation is a native crash (e.g. inside a C extension during image decoding) that bypasses Python's exception handling entirely — that kind of crash can't be caught by any try/except in the Python code, including the one added last time.

What this round actually does, since I can't fix something I can't observe:

  • "Open Log Folder" button added to the Help screen — you mentioned you couldn't find the log file; this opens it directly (%APPDATA%\bulk-image-organizer\logs\ on Windows) so it's no longer something you have to hunt for manually.
  • The "Duplicate Scan Error" dialog (for any catchable failure) now also prints the resolved log file path directly in the dialog text.
  • Added checkpoint logging around scan start and the worker's run loop, so if it crashes again, whatever made it into the log before the crash will show exactly how far it got.
  • Added a defensive try/except around the per-image hashing call inside the scan loop, in case some unusual file triggers an exception type outside the set _compute_hashes() already catches — this degrades to "skip this one file" instead of risking the whole scan, on the chance the cause is a Python-level exception after all.

If you're willing to retest: please try the scan again from this branch and, whether it crashes or not, check Help → Open Log Folder for bulk-image-organizer.log and share its last ~20 lines (especially anything after "Dupe scan requested"). That would tell us conclusively whether this is a catchable Python error we can now fix directly, or a native crash that needs a different approach (e.g. isolating the hashing step in a subprocess so a hard crash there can't take the whole app down). Re-opening was the right call — leaving this open until we have that confirmation either way.

Thanks for testing the previous fix and reporting back — sorry that one didn't land. Continued on branch `0.1.47/issue-111-86-64-89-feedback-fixes` (chained after the dev work in progress). **I want to be upfront: I could not reproduce this crash** from this (Linux, source-run) development environment, and I don't have access to a Windows machine to test the packaged build directly. I diffed the actual application code between the `v0.1.35` and `v0.1.36` tags and found nothing touching the dupe-scan path (`_start_dupe_scan`, `DupeWorker`, hashing) — so I don't think this was a code regression introduced between those two versions; it looks like a pre-existing issue that happened to surface around when you upgraded. Given the prior fix's try/except wrapping apparently never triggered (no dialog appeared, matching your report of "no perceivable change"), the most likely explanation is a **native crash** (e.g. inside a C extension during image decoding) that bypasses Python's exception handling entirely — that kind of crash can't be caught by any `try/except` in the Python code, including the one added last time. What this round actually does, since I can't fix something I can't observe: - **"Open Log Folder" button** added to the Help screen — you mentioned you couldn't find the log file; this opens it directly (`%APPDATA%\bulk-image-organizer\logs\` on Windows) so it's no longer something you have to hunt for manually. - The "Duplicate Scan Error" dialog (for any *catchable* failure) now also prints the resolved log file path directly in the dialog text. - Added checkpoint logging around scan start and the worker's run loop, so if it crashes again, whatever made it into the log before the crash will show exactly how far it got. - Added a defensive `try/except` around the per-image hashing call inside the scan loop, in case some unusual file triggers an exception type outside the set `_compute_hashes()` already catches — this degrades to "skip this one file" instead of risking the whole scan, on the chance the cause is a Python-level exception after all. **If you're willing to retest**: please try the scan again from this branch and, whether it crashes or not, check **Help → Open Log Folder** for `bulk-image-organizer.log` and share its last ~20 lines (especially anything after "Dupe scan requested"). That would tell us conclusively whether this is a catchable Python error we can now fix directly, or a native crash that needs a different approach (e.g. isolating the hashing step in a subprocess so a hard crash there can't take the whole app down). Re-opening was the right call — leaving this open until we have that confirmation either way.
Author
Owner

Here's the full log from launching the application, opening a directory, and initiating a scan then crash:

2026-06-20 15:12:24,503 | INFO     | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.48 Beta
2026-06-20 15:12:24,736 | INFO     | bulk_image_organizer.main_window | main_window.py:319 | __init__() | MainWindow initialized (PR13 configuration milestone)
2026-06-20 15:12:24,868 | INFO     | bulk_image_organizer.main | main.py:98 | main() | Main window shown
2026-06-20 15:13:03,100 | INFO     | bulk_image_organizer.main_window | main_window.py:3743 | open_directory() | Preloaded 17 rows from working DB for D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:13:03,101 | INFO     | bulk_image_organizer.main_window | main_window.py:3747 | open_directory() | Hydrated 17 cached thumbnails into grid for D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:13:03,121 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:13:03,127 | INFO     | bulk_image_organizer.main_window | main_window.py:3851 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:13:03,127 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:13:03,181 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 57, 'seeded': 57, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['bubbles.jpg', 'ferric-rainbow-25.jpg', 'anen.jpg', 'into-forever-25.jpg', 'fireworks-25.jpg', 'ley-lines-25.jpg', 'blood-price-25.jpg', 'cosmic-forces-25.jpg', 'intermission-25.jpg', 'edge-25.jpg', 'hemispheres-25.jpg', 'innocence-25.jpg', 'fish-skeleton-25.jpg', 'bluebird-25.jpg', 'Cerulean.jpg', 'lethe-25.jpg', 'corona-25.jpg', 'Blossom.jpg', 'fluorescence6.jpg', 'Big.jpg', 'corkscrew-25.jpg', 'bloom-25.jpg', 'interstellar-25.jpg', 'brainwave-25.jpg', 'somethingblue.jpg', 'starbirth2x2560.jpg', 'copperwire-25.jpg', 'AllienMushroom_v2_fullsize.jpg', 'dynamo-25.jpg', 'glory-25.jpg', 'lichens-25.jpg', 'firething-25.jpg', 'fish-head-25.jpg', 'linear-dimensions-25.jpg', 'Asteroids.jpg', 'once1600.jpg', 'light-fantastic-25.jpg', 'dreaming-25.jpg', 'glassworks-25.jpg', 'golden-egg-closeup-25.jpg', 'hillsong-25.jpg', 'blue%20sphere_fullsize.jpg', 'amazed1600.jpg', 'heliograph-25.jpg', 'drift-25.jpg', 'hellid-25.jpg', 'blue-outpost-25.jpg', 'starbirth-Cropped.jpg', 'windowsxp_glass_blue.jpg', 'glassworks-bg7-25.jpg', 'cobaltdaisy.jpg', 'invisible-25.jpg', 'Splash.jpg', 'helping-hands-25.jpg', 'dreamcatcher-25.jpg', 'gold-dragon-25.jpg', 'corporeal-25.jpg'], 'changed_paths': []}
2026-06-20 15:13:03,243 | INFO     | bulk_image_organizer.main_window | main_window.py:3978 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['bubbles.jpg', 'ferric-rainbow-25.jpg', 'anen.jpg', 'into-forever-25.jpg', 'fireworks-25.jpg', 'ley-lines-25.jpg', 'blood-price-25.jpg', 'cosmic-forces-25.jpg', 'intermission-25.jpg', 'edge-25.jpg', 'hemispheres-25.jpg', 'innocence-25.jpg', 'fish-skeleton-25.jpg', 'bluebird-25.jpg', 'Cerulean.jpg', 'lethe-25.jpg', 'corona-25.jpg', 'Blossom.jpg', 'fluorescence6.jpg', 'Big.jpg', 'corkscrew-25.jpg', 'bloom-25.jpg', 'interstellar-25.jpg', 'brainwave-25.jpg', 'somethingblue.jpg', 'starbirth2x2560.jpg', 'copperwire-25.jpg', 'AllienMushroom_v2_fullsize.jpg', 'dynamo-25.jpg', 'glory-25.jpg', 'lichens-25.jpg', 'firething-25.jpg', 'fish-head-25.jpg', 'linear-dimensions-25.jpg', 'Asteroids.jpg', 'once1600.jpg', 'light-fantastic-25.jpg', 'dreaming-25.jpg', 'glassworks-25.jpg', 'golden-egg-closeup-25.jpg', 'hillsong-25.jpg', 'blue%20sphere_fullsize.jpg', 'amazed1600.jpg', 'heliograph-25.jpg', 'drift-25.jpg', 'hellid-25.jpg', 'blue-outpost-25.jpg', 'starbirth-Cropped.jpg', 'windowsxp_glass_blue.jpg', 'glassworks-bg7-25.jpg', 'cobaltdaisy.jpg', 'invisible-25.jpg', 'Splash.jpg', 'helping-hands-25.jpg', 'dreamcatcher-25.jpg', 'gold-dragon-25.jpg', 'corporeal-25.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 57, 'total': 57}
2026-06-20 15:13:03,294 | DEBUG    | PIL.Image | Image.py:421 | _import_plugin_for_extension() | Importing JpegImagePlugin
2026-06-20 15:13:05,087 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 40, 'added': 40, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 40, 'errors': [], 'total_scanned': 57, 'cancelled': False, 'scan_type': 'metadata'}
2026-06-20 15:13:22,192 | INFO     | bulk_image_organizer.main_window | main_window.py:2402 | _start_dupe_scan() | Dupe scan requested: kind=exact root=D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:13:22,195 | INFO     | bulk_image_organizer.main_window | main_window.py:2425 | _start_dupe_scan() | Dupe scan worker constructed; submitting to thread pool
2026-06-20 15:13:22,195 | INFO     | bulk_image_organizer.main_window | main_window.py:2427 | _start_dupe_scan() | Dupe scan worker submitted
2026-06-20 15:13:22,195 | INFO     | bulk_image_organizer.dupe_worker | dupe_worker.py:57 | run() | DupeWorker.run() starting: kind=exact root=D:\StagingArea\Desktop Backgrounds\Good Walpapers

Here's the content of the directory that was open

PS D:\StagingArea\Desktop Backgrounds\Good Walpapers> dir

    Directory: D:\StagingArea\Desktop Backgrounds\Good Walpapers

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---           6/20/2026  8:48 AM         434176 .bulk_image_organizer.db
-a---           8/28/2003  9:23 PM         205685 AllienMushroom_v2_fullsize.jpg
-a---            9/1/2004  9:30 PM         938002 amazed1600.jpg
-a---           8/28/2003  9:22 PM         792937 anen.jpg
-a---            9/1/2004 10:12 PM        1081001 Asteroids.jpg
-a---          10/22/2003  4:31 AM         583532 Big.jpg
-a---           4/30/2007  5:13 PM        2185983 blood-price-25.jpg
-a---          12/18/2006 12:56 PM        1737080 bloom-25.jpg
-a---           8/28/2003 10:07 PM         557103 Blossom.jpg
-a---          12/18/2006 12:55 PM        3178385 blue-outpost-25.jpg
-a---           8/28/2003 10:07 PM         789861 blue%20sphere_fullsize.jpg
-a---           4/15/2007 11:15 PM        2129813 bluebird-25.jpg
-a---           9/23/2007  4:39 PM        1135381 brainwave-25.jpg
-a---           3/13/2004  1:46 PM          70141 bubbles.jpg
-a---           7/10/2004  5:37 PM         253635 Cerulean.jpg
-a---           2/26/2003  7:15 PM         302291 cobaltdaisy.jpg
-a---           4/15/2007  5:01 PM        1207899 copperwire-25.jpg
-a---            4/2/2007  1:41 AM        1866658 corkscrew-25.jpg
-a---            4/2/2007  1:43 AM        2086347 corona-25.jpg
-a---            4/6/2007 10:44 PM        2011344 corporeal-25.jpg
-a---           4/30/2007  2:40 PM        1944895 cosmic-forces-25.jpg
-a---           12/2/2008  9:26 PM        2204800 dreamcatcher-25.jpg
-a---           4/19/2007 11:10 PM        1586397 dreaming-25.jpg
-a---          12/31/2007  9:52 PM        2415749 drift-25.jpg
-a---           9/23/2007  4:55 PM        2090253 dynamo-25.jpg
-a---           2/26/2009  9:51 PM        1714408 edge-25.jpg
-a---          12/18/2006 12:57 PM        1806772 ferric-rainbow-25.jpg
-a---           5/31/2007 10:45 PM        1735572 firething-25.jpg
-a---            4/2/2007 12:59 AM        1367388 fireworks-25.jpg
-a---            4/6/2007 10:46 PM        1093836 fish-head-25.jpg
-a---           4/10/2007 12:53 PM         870211 fish-skeleton-25.jpg
-a---           2/26/2003  7:13 PM         168706 fluorescence6.jpg
-a---          12/18/2006 12:56 PM        1359946 glassworks-25.jpg
-a---          12/18/2006 12:56 PM        1718520 glassworks-bg7-25.jpg
-a---          12/18/2006 12:57 PM        1916622 glory-25.jpg
-a---            4/2/2007 12:51 AM        2061480 gold-dragon-25.jpg
-a---           4/20/2007  9:34 PM        1538003 golden-egg-closeup-25.jpg
-a---            4/2/2007  1:49 AM        2295212 heliograph-25.jpg
-a---           9/23/2007  4:48 PM        2200426 hellid-25.jpg
-a---            4/2/2007  2:01 AM        1416002 helping-hands-25.jpg
-a---          12/18/2006 12:56 PM        1589590 hemispheres-25.jpg
-a---           2/26/2009  9:48 PM        2605198 hillsong-25.jpg
-a---          12/18/2006 12:57 PM         809871 innocence-25.jpg
-a---          12/19/2006  6:12 PM         535073 intermission-25.jpg
-a---           2/29/2008  7:31 PM        1724086 interstellar-25.jpg
-a---            4/6/2007 11:44 PM         887099 into-forever-25.jpg
-a---          12/18/2006 12:56 PM        2095224 invisible-25.jpg
-a---           2/29/2008  5:25 PM        1828619 lethe-25.jpg
-a---          12/18/2006 12:56 PM        1535081 ley-lines-25.jpg
-a---          12/18/2006 12:56 PM        2277982 lichens-25.jpg
-a---          12/18/2006 12:56 PM        1364959 light-fantastic-25.jpg
-a---            4/2/2007 12:56 AM        1283186 linear-dimensions-25.jpg
-a---            9/1/2004  9:20 PM         817499 once1600.jpg
-a---           2/26/2003  7:14 PM         428949 somethingblue.jpg
-a---          10/15/2006 10:03 PM         104867 Splash.jpg
-a---            8/6/2006 12:15 AM         125367 starbirth-Cropped.jpg
-a---            9/1/2004 10:12 PM         410437 starbirth2x2560.jpg
-a---            7/5/2003  1:10 AM         268090 windowsxp_glass_blue.jpg

Running version 0.1.36 Beta and repeating generated this log before crashing:

2026-06-20 15:17:22,809 | INFO     | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.36 Beta
2026-06-20 15:17:22,943 | INFO     | bulk_image_organizer.main_window | main_window.py:294 | __init__() | MainWindow initialized (PR13 configuration milestone)
2026-06-20 15:17:23,080 | INFO     | bulk_image_organizer.main | main.py:98 | main() | Main window shown
2026-06-20 15:17:31,605 | INFO     | bulk_image_organizer.main_window | main_window.py:3576 | open_directory() | Preloaded 57 rows from working DB for D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:17:31,609 | INFO     | bulk_image_organizer.main_window | main_window.py:3580 | open_directory() | Hydrated 57 cached thumbnails into grid for D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:17:31,624 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:17:31,625 | INFO     | bulk_image_organizer.main_window | main_window.py:3683 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:17:31,625 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:17:31,683 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 57, 'seeded': 57, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['Big.jpg', 'golden-egg-closeup-25.jpg', 'lethe-25.jpg', 'somethingblue.jpg', 'anen.jpg', 'bubbles.jpg', 'helping-hands-25.jpg', 'glory-25.jpg', 'bluebird-25.jpg', 'Cerulean.jpg', 'dynamo-25.jpg', 'firething-25.jpg', 'fluorescence6.jpg', 'hellid-25.jpg', 'bloom-25.jpg', 'cosmic-forces-25.jpg', 'into-forever-25.jpg', 'hemispheres-25.jpg', 'gold-dragon-25.jpg', 'AllienMushroom_v2_fullsize.jpg', 'light-fantastic-25.jpg', 'corkscrew-25.jpg', 'drift-25.jpg', 'glassworks-bg7-25.jpg', 'lichens-25.jpg', 'cobaltdaisy.jpg', 'innocence-25.jpg', 'copperwire-25.jpg', 'Asteroids.jpg', 'dreaming-25.jpg', 'edge-25.jpg', 'corporeal-25.jpg', 'corona-25.jpg', 'starbirth2x2560.jpg', 'fireworks-25.jpg', 'interstellar-25.jpg', 'linear-dimensions-25.jpg', 'fish-head-25.jpg', 'brainwave-25.jpg', 'ley-lines-25.jpg', 'Blossom.jpg', 'windowsxp_glass_blue.jpg', 'once1600.jpg', 'Splash.jpg', 'ferric-rainbow-25.jpg', 'blue%20sphere_fullsize.jpg', 'fish-skeleton-25.jpg', 'heliograph-25.jpg', 'dreamcatcher-25.jpg', 'amazed1600.jpg', 'blue-outpost-25.jpg', 'glassworks-25.jpg', 'starbirth-Cropped.jpg', 'intermission-25.jpg', 'invisible-25.jpg', 'hillsong-25.jpg', 'blood-price-25.jpg'], 'changed_paths': []}
2026-06-20 15:17:31,725 | INFO     | bulk_image_organizer.main_window | main_window.py:3810 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['Big.jpg', 'golden-egg-closeup-25.jpg', 'lethe-25.jpg', 'somethingblue.jpg', 'anen.jpg', 'bubbles.jpg', 'helping-hands-25.jpg', 'glory-25.jpg', 'bluebird-25.jpg', 'Cerulean.jpg', 'dynamo-25.jpg', 'firething-25.jpg', 'fluorescence6.jpg', 'hellid-25.jpg', 'bloom-25.jpg', 'cosmic-forces-25.jpg', 'into-forever-25.jpg', 'hemispheres-25.jpg', 'gold-dragon-25.jpg', 'AllienMushroom_v2_fullsize.jpg', 'light-fantastic-25.jpg', 'corkscrew-25.jpg', 'drift-25.jpg', 'glassworks-bg7-25.jpg', 'lichens-25.jpg', 'cobaltdaisy.jpg', 'innocence-25.jpg', 'copperwire-25.jpg', 'Asteroids.jpg', 'dreaming-25.jpg', 'edge-25.jpg', 'corporeal-25.jpg', 'corona-25.jpg', 'starbirth2x2560.jpg', 'fireworks-25.jpg', 'interstellar-25.jpg', 'linear-dimensions-25.jpg', 'fish-head-25.jpg', 'brainwave-25.jpg', 'ley-lines-25.jpg', 'Blossom.jpg', 'windowsxp_glass_blue.jpg', 'once1600.jpg', 'Splash.jpg', 'ferric-rainbow-25.jpg', 'blue%20sphere_fullsize.jpg', 'fish-skeleton-25.jpg', 'heliograph-25.jpg', 'dreamcatcher-25.jpg', 'amazed1600.jpg', 'blue-outpost-25.jpg', 'glassworks-25.jpg', 'starbirth-Cropped.jpg', 'intermission-25.jpg', 'invisible-25.jpg', 'hillsong-25.jpg', 'blood-price-25.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 57, 'total': 57}
2026-06-20 15:17:31,759 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 0, 'added': 0, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 0, 'errors': [], 'total_scanned': 57, 'cancelled': False, 'scan_type': 'metadata'}
2026-06-20 15:17:35,369 | DEBUG    | PIL.Image | Image.py:421 | _import_plugin_for_extension() | Importing JpegImagePlugin

Version 0.1.35 Beta completed the scan and displayed results

2026-06-20 15:18:26,603 | INFO     | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.35 Beta
2026-06-20 15:18:26,740 | INFO     | bulk_image_organizer.main_window | main_window.py:294 | __init__() | MainWindow initialized (PR13 configuration milestone)
2026-06-20 15:18:26,887 | INFO     | bulk_image_organizer.main | main.py:98 | main() | Main window shown
2026-06-20 15:18:47,080 | INFO     | bulk_image_organizer.main_window | main_window.py:3572 | open_directory() | Preloaded 57 rows from working DB for D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:18:47,084 | INFO     | bulk_image_organizer.main_window | main_window.py:3576 | open_directory() | Hydrated 57 cached thumbnails into grid for D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:18:47,097 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:18:47,099 | INFO     | bulk_image_organizer.main_window | main_window.py:3679 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:18:47,099 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers
2026-06-20 15:18:47,151 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 57, 'seeded': 57, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['glassworks-bg7-25.jpg', 'hillsong-25.jpg', 'linear-dimensions-25.jpg', 'starbirth2x2560.jpg', 'windowsxp_glass_blue.jpg', 'bloom-25.jpg', 'ferric-rainbow-25.jpg', 'invisible-25.jpg', 'cosmic-forces-25.jpg', 'heliograph-25.jpg', 'golden-egg-closeup-25.jpg', 'Big.jpg', 'fish-skeleton-25.jpg', 'edge-25.jpg', 'starbirth-Cropped.jpg', 'bubbles.jpg', 'fish-head-25.jpg', 'interstellar-25.jpg', 'blood-price-25.jpg', 'Blossom.jpg', 'ley-lines-25.jpg', 'firething-25.jpg', 'amazed1600.jpg', 'bluebird-25.jpg', 'corona-25.jpg', 'somethingblue.jpg', 'gold-dragon-25.jpg', 'glory-25.jpg', 'Cerulean.jpg', 'dreaming-25.jpg', 'corporeal-25.jpg', 'corkscrew-25.jpg', 'once1600.jpg', 'AllienMushroom_v2_fullsize.jpg', 'fluorescence6.jpg', 'fireworks-25.jpg', 'intermission-25.jpg', 'dynamo-25.jpg', 'copperwire-25.jpg', 'Splash.jpg', 'glassworks-25.jpg', 'helping-hands-25.jpg', 'brainwave-25.jpg', 'dreamcatcher-25.jpg', 'innocence-25.jpg', 'lethe-25.jpg', 'light-fantastic-25.jpg', 'hemispheres-25.jpg', 'lichens-25.jpg', 'blue%20sphere_fullsize.jpg', 'drift-25.jpg', 'cobaltdaisy.jpg', 'anen.jpg', 'into-forever-25.jpg', 'blue-outpost-25.jpg', 'hellid-25.jpg', 'Asteroids.jpg'], 'changed_paths': []}
2026-06-20 15:18:47,180 | INFO     | bulk_image_organizer.main_window | main_window.py:3806 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['glassworks-bg7-25.jpg', 'hillsong-25.jpg', 'linear-dimensions-25.jpg', 'starbirth2x2560.jpg', 'windowsxp_glass_blue.jpg', 'bloom-25.jpg', 'ferric-rainbow-25.jpg', 'invisible-25.jpg', 'cosmic-forces-25.jpg', 'heliograph-25.jpg', 'golden-egg-closeup-25.jpg', 'Big.jpg', 'fish-skeleton-25.jpg', 'edge-25.jpg', 'starbirth-Cropped.jpg', 'bubbles.jpg', 'fish-head-25.jpg', 'interstellar-25.jpg', 'blood-price-25.jpg', 'Blossom.jpg', 'ley-lines-25.jpg', 'firething-25.jpg', 'amazed1600.jpg', 'bluebird-25.jpg', 'corona-25.jpg', 'somethingblue.jpg', 'gold-dragon-25.jpg', 'glory-25.jpg', 'Cerulean.jpg', 'dreaming-25.jpg', 'corporeal-25.jpg', 'corkscrew-25.jpg', 'once1600.jpg', 'AllienMushroom_v2_fullsize.jpg', 'fluorescence6.jpg', 'fireworks-25.jpg', 'intermission-25.jpg', 'dynamo-25.jpg', 'copperwire-25.jpg', 'Splash.jpg', 'glassworks-25.jpg', 'helping-hands-25.jpg', 'brainwave-25.jpg', 'dreamcatcher-25.jpg', 'innocence-25.jpg', 'lethe-25.jpg', 'light-fantastic-25.jpg', 'hemispheres-25.jpg', 'lichens-25.jpg', 'blue%20sphere_fullsize.jpg', 'drift-25.jpg', 'cobaltdaisy.jpg', 'anen.jpg', 'into-forever-25.jpg', 'blue-outpost-25.jpg', 'hellid-25.jpg', 'Asteroids.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 57, 'total': 57}
2026-06-20 15:18:47,216 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 0, 'added': 0, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 0, 'errors': [], 'total_scanned': 57, 'cancelled': False, 'scan_type': 'metadata'}
2026-06-20 15:18:50,592 | DEBUG    | PIL.Image | Image.py:421 | _import_plugin_for_extension() | Importing JpegImagePlugin
Here's the full log from launching the application, opening a directory, and initiating a scan then crash: ``` 2026-06-20 15:12:24,503 | INFO | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.48 Beta 2026-06-20 15:12:24,736 | INFO | bulk_image_organizer.main_window | main_window.py:319 | __init__() | MainWindow initialized (PR13 configuration milestone) 2026-06-20 15:12:24,868 | INFO | bulk_image_organizer.main | main.py:98 | main() | Main window shown 2026-06-20 15:13:03,100 | INFO | bulk_image_organizer.main_window | main_window.py:3743 | open_directory() | Preloaded 17 rows from working DB for D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:13:03,101 | INFO | bulk_image_organizer.main_window | main_window.py:3747 | open_directory() | Hydrated 17 cached thumbnails into grid for D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:13:03,121 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:13:03,127 | INFO | bulk_image_organizer.main_window | main_window.py:3851 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:13:03,127 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:13:03,181 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 57, 'seeded': 57, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['bubbles.jpg', 'ferric-rainbow-25.jpg', 'anen.jpg', 'into-forever-25.jpg', 'fireworks-25.jpg', 'ley-lines-25.jpg', 'blood-price-25.jpg', 'cosmic-forces-25.jpg', 'intermission-25.jpg', 'edge-25.jpg', 'hemispheres-25.jpg', 'innocence-25.jpg', 'fish-skeleton-25.jpg', 'bluebird-25.jpg', 'Cerulean.jpg', 'lethe-25.jpg', 'corona-25.jpg', 'Blossom.jpg', 'fluorescence6.jpg', 'Big.jpg', 'corkscrew-25.jpg', 'bloom-25.jpg', 'interstellar-25.jpg', 'brainwave-25.jpg', 'somethingblue.jpg', 'starbirth2x2560.jpg', 'copperwire-25.jpg', 'AllienMushroom_v2_fullsize.jpg', 'dynamo-25.jpg', 'glory-25.jpg', 'lichens-25.jpg', 'firething-25.jpg', 'fish-head-25.jpg', 'linear-dimensions-25.jpg', 'Asteroids.jpg', 'once1600.jpg', 'light-fantastic-25.jpg', 'dreaming-25.jpg', 'glassworks-25.jpg', 'golden-egg-closeup-25.jpg', 'hillsong-25.jpg', 'blue%20sphere_fullsize.jpg', 'amazed1600.jpg', 'heliograph-25.jpg', 'drift-25.jpg', 'hellid-25.jpg', 'blue-outpost-25.jpg', 'starbirth-Cropped.jpg', 'windowsxp_glass_blue.jpg', 'glassworks-bg7-25.jpg', 'cobaltdaisy.jpg', 'invisible-25.jpg', 'Splash.jpg', 'helping-hands-25.jpg', 'dreamcatcher-25.jpg', 'gold-dragon-25.jpg', 'corporeal-25.jpg'], 'changed_paths': []} 2026-06-20 15:13:03,243 | INFO | bulk_image_organizer.main_window | main_window.py:3978 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['bubbles.jpg', 'ferric-rainbow-25.jpg', 'anen.jpg', 'into-forever-25.jpg', 'fireworks-25.jpg', 'ley-lines-25.jpg', 'blood-price-25.jpg', 'cosmic-forces-25.jpg', 'intermission-25.jpg', 'edge-25.jpg', 'hemispheres-25.jpg', 'innocence-25.jpg', 'fish-skeleton-25.jpg', 'bluebird-25.jpg', 'Cerulean.jpg', 'lethe-25.jpg', 'corona-25.jpg', 'Blossom.jpg', 'fluorescence6.jpg', 'Big.jpg', 'corkscrew-25.jpg', 'bloom-25.jpg', 'interstellar-25.jpg', 'brainwave-25.jpg', 'somethingblue.jpg', 'starbirth2x2560.jpg', 'copperwire-25.jpg', 'AllienMushroom_v2_fullsize.jpg', 'dynamo-25.jpg', 'glory-25.jpg', 'lichens-25.jpg', 'firething-25.jpg', 'fish-head-25.jpg', 'linear-dimensions-25.jpg', 'Asteroids.jpg', 'once1600.jpg', 'light-fantastic-25.jpg', 'dreaming-25.jpg', 'glassworks-25.jpg', 'golden-egg-closeup-25.jpg', 'hillsong-25.jpg', 'blue%20sphere_fullsize.jpg', 'amazed1600.jpg', 'heliograph-25.jpg', 'drift-25.jpg', 'hellid-25.jpg', 'blue-outpost-25.jpg', 'starbirth-Cropped.jpg', 'windowsxp_glass_blue.jpg', 'glassworks-bg7-25.jpg', 'cobaltdaisy.jpg', 'invisible-25.jpg', 'Splash.jpg', 'helping-hands-25.jpg', 'dreamcatcher-25.jpg', 'gold-dragon-25.jpg', 'corporeal-25.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 57, 'total': 57} 2026-06-20 15:13:03,294 | DEBUG | PIL.Image | Image.py:421 | _import_plugin_for_extension() | Importing JpegImagePlugin 2026-06-20 15:13:05,087 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 40, 'added': 40, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 40, 'errors': [], 'total_scanned': 57, 'cancelled': False, 'scan_type': 'metadata'} 2026-06-20 15:13:22,192 | INFO | bulk_image_organizer.main_window | main_window.py:2402 | _start_dupe_scan() | Dupe scan requested: kind=exact root=D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:13:22,195 | INFO | bulk_image_organizer.main_window | main_window.py:2425 | _start_dupe_scan() | Dupe scan worker constructed; submitting to thread pool 2026-06-20 15:13:22,195 | INFO | bulk_image_organizer.main_window | main_window.py:2427 | _start_dupe_scan() | Dupe scan worker submitted 2026-06-20 15:13:22,195 | INFO | bulk_image_organizer.dupe_worker | dupe_worker.py:57 | run() | DupeWorker.run() starting: kind=exact root=D:\StagingArea\Desktop Backgrounds\Good Walpapers ``` Here's the content of the directory that was open ``` PS D:\StagingArea\Desktop Backgrounds\Good Walpapers> dir Directory: D:\StagingArea\Desktop Backgrounds\Good Walpapers Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 6/20/2026 8:48 AM 434176 .bulk_image_organizer.db -a--- 8/28/2003 9:23 PM 205685 AllienMushroom_v2_fullsize.jpg -a--- 9/1/2004 9:30 PM 938002 amazed1600.jpg -a--- 8/28/2003 9:22 PM 792937 anen.jpg -a--- 9/1/2004 10:12 PM 1081001 Asteroids.jpg -a--- 10/22/2003 4:31 AM 583532 Big.jpg -a--- 4/30/2007 5:13 PM 2185983 blood-price-25.jpg -a--- 12/18/2006 12:56 PM 1737080 bloom-25.jpg -a--- 8/28/2003 10:07 PM 557103 Blossom.jpg -a--- 12/18/2006 12:55 PM 3178385 blue-outpost-25.jpg -a--- 8/28/2003 10:07 PM 789861 blue%20sphere_fullsize.jpg -a--- 4/15/2007 11:15 PM 2129813 bluebird-25.jpg -a--- 9/23/2007 4:39 PM 1135381 brainwave-25.jpg -a--- 3/13/2004 1:46 PM 70141 bubbles.jpg -a--- 7/10/2004 5:37 PM 253635 Cerulean.jpg -a--- 2/26/2003 7:15 PM 302291 cobaltdaisy.jpg -a--- 4/15/2007 5:01 PM 1207899 copperwire-25.jpg -a--- 4/2/2007 1:41 AM 1866658 corkscrew-25.jpg -a--- 4/2/2007 1:43 AM 2086347 corona-25.jpg -a--- 4/6/2007 10:44 PM 2011344 corporeal-25.jpg -a--- 4/30/2007 2:40 PM 1944895 cosmic-forces-25.jpg -a--- 12/2/2008 9:26 PM 2204800 dreamcatcher-25.jpg -a--- 4/19/2007 11:10 PM 1586397 dreaming-25.jpg -a--- 12/31/2007 9:52 PM 2415749 drift-25.jpg -a--- 9/23/2007 4:55 PM 2090253 dynamo-25.jpg -a--- 2/26/2009 9:51 PM 1714408 edge-25.jpg -a--- 12/18/2006 12:57 PM 1806772 ferric-rainbow-25.jpg -a--- 5/31/2007 10:45 PM 1735572 firething-25.jpg -a--- 4/2/2007 12:59 AM 1367388 fireworks-25.jpg -a--- 4/6/2007 10:46 PM 1093836 fish-head-25.jpg -a--- 4/10/2007 12:53 PM 870211 fish-skeleton-25.jpg -a--- 2/26/2003 7:13 PM 168706 fluorescence6.jpg -a--- 12/18/2006 12:56 PM 1359946 glassworks-25.jpg -a--- 12/18/2006 12:56 PM 1718520 glassworks-bg7-25.jpg -a--- 12/18/2006 12:57 PM 1916622 glory-25.jpg -a--- 4/2/2007 12:51 AM 2061480 gold-dragon-25.jpg -a--- 4/20/2007 9:34 PM 1538003 golden-egg-closeup-25.jpg -a--- 4/2/2007 1:49 AM 2295212 heliograph-25.jpg -a--- 9/23/2007 4:48 PM 2200426 hellid-25.jpg -a--- 4/2/2007 2:01 AM 1416002 helping-hands-25.jpg -a--- 12/18/2006 12:56 PM 1589590 hemispheres-25.jpg -a--- 2/26/2009 9:48 PM 2605198 hillsong-25.jpg -a--- 12/18/2006 12:57 PM 809871 innocence-25.jpg -a--- 12/19/2006 6:12 PM 535073 intermission-25.jpg -a--- 2/29/2008 7:31 PM 1724086 interstellar-25.jpg -a--- 4/6/2007 11:44 PM 887099 into-forever-25.jpg -a--- 12/18/2006 12:56 PM 2095224 invisible-25.jpg -a--- 2/29/2008 5:25 PM 1828619 lethe-25.jpg -a--- 12/18/2006 12:56 PM 1535081 ley-lines-25.jpg -a--- 12/18/2006 12:56 PM 2277982 lichens-25.jpg -a--- 12/18/2006 12:56 PM 1364959 light-fantastic-25.jpg -a--- 4/2/2007 12:56 AM 1283186 linear-dimensions-25.jpg -a--- 9/1/2004 9:20 PM 817499 once1600.jpg -a--- 2/26/2003 7:14 PM 428949 somethingblue.jpg -a--- 10/15/2006 10:03 PM 104867 Splash.jpg -a--- 8/6/2006 12:15 AM 125367 starbirth-Cropped.jpg -a--- 9/1/2004 10:12 PM 410437 starbirth2x2560.jpg -a--- 7/5/2003 1:10 AM 268090 windowsxp_glass_blue.jpg ``` Running version `0.1.36 Beta` and repeating generated this log before crashing: ``` 2026-06-20 15:17:22,809 | INFO | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.36 Beta 2026-06-20 15:17:22,943 | INFO | bulk_image_organizer.main_window | main_window.py:294 | __init__() | MainWindow initialized (PR13 configuration milestone) 2026-06-20 15:17:23,080 | INFO | bulk_image_organizer.main | main.py:98 | main() | Main window shown 2026-06-20 15:17:31,605 | INFO | bulk_image_organizer.main_window | main_window.py:3576 | open_directory() | Preloaded 57 rows from working DB for D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:17:31,609 | INFO | bulk_image_organizer.main_window | main_window.py:3580 | open_directory() | Hydrated 57 cached thumbnails into grid for D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:17:31,624 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:17:31,625 | INFO | bulk_image_organizer.main_window | main_window.py:3683 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:17:31,625 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:17:31,683 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 57, 'seeded': 57, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['Big.jpg', 'golden-egg-closeup-25.jpg', 'lethe-25.jpg', 'somethingblue.jpg', 'anen.jpg', 'bubbles.jpg', 'helping-hands-25.jpg', 'glory-25.jpg', 'bluebird-25.jpg', 'Cerulean.jpg', 'dynamo-25.jpg', 'firething-25.jpg', 'fluorescence6.jpg', 'hellid-25.jpg', 'bloom-25.jpg', 'cosmic-forces-25.jpg', 'into-forever-25.jpg', 'hemispheres-25.jpg', 'gold-dragon-25.jpg', 'AllienMushroom_v2_fullsize.jpg', 'light-fantastic-25.jpg', 'corkscrew-25.jpg', 'drift-25.jpg', 'glassworks-bg7-25.jpg', 'lichens-25.jpg', 'cobaltdaisy.jpg', 'innocence-25.jpg', 'copperwire-25.jpg', 'Asteroids.jpg', 'dreaming-25.jpg', 'edge-25.jpg', 'corporeal-25.jpg', 'corona-25.jpg', 'starbirth2x2560.jpg', 'fireworks-25.jpg', 'interstellar-25.jpg', 'linear-dimensions-25.jpg', 'fish-head-25.jpg', 'brainwave-25.jpg', 'ley-lines-25.jpg', 'Blossom.jpg', 'windowsxp_glass_blue.jpg', 'once1600.jpg', 'Splash.jpg', 'ferric-rainbow-25.jpg', 'blue%20sphere_fullsize.jpg', 'fish-skeleton-25.jpg', 'heliograph-25.jpg', 'dreamcatcher-25.jpg', 'amazed1600.jpg', 'blue-outpost-25.jpg', 'glassworks-25.jpg', 'starbirth-Cropped.jpg', 'intermission-25.jpg', 'invisible-25.jpg', 'hillsong-25.jpg', 'blood-price-25.jpg'], 'changed_paths': []} 2026-06-20 15:17:31,725 | INFO | bulk_image_organizer.main_window | main_window.py:3810 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['Big.jpg', 'golden-egg-closeup-25.jpg', 'lethe-25.jpg', 'somethingblue.jpg', 'anen.jpg', 'bubbles.jpg', 'helping-hands-25.jpg', 'glory-25.jpg', 'bluebird-25.jpg', 'Cerulean.jpg', 'dynamo-25.jpg', 'firething-25.jpg', 'fluorescence6.jpg', 'hellid-25.jpg', 'bloom-25.jpg', 'cosmic-forces-25.jpg', 'into-forever-25.jpg', 'hemispheres-25.jpg', 'gold-dragon-25.jpg', 'AllienMushroom_v2_fullsize.jpg', 'light-fantastic-25.jpg', 'corkscrew-25.jpg', 'drift-25.jpg', 'glassworks-bg7-25.jpg', 'lichens-25.jpg', 'cobaltdaisy.jpg', 'innocence-25.jpg', 'copperwire-25.jpg', 'Asteroids.jpg', 'dreaming-25.jpg', 'edge-25.jpg', 'corporeal-25.jpg', 'corona-25.jpg', 'starbirth2x2560.jpg', 'fireworks-25.jpg', 'interstellar-25.jpg', 'linear-dimensions-25.jpg', 'fish-head-25.jpg', 'brainwave-25.jpg', 'ley-lines-25.jpg', 'Blossom.jpg', 'windowsxp_glass_blue.jpg', 'once1600.jpg', 'Splash.jpg', 'ferric-rainbow-25.jpg', 'blue%20sphere_fullsize.jpg', 'fish-skeleton-25.jpg', 'heliograph-25.jpg', 'dreamcatcher-25.jpg', 'amazed1600.jpg', 'blue-outpost-25.jpg', 'glassworks-25.jpg', 'starbirth-Cropped.jpg', 'intermission-25.jpg', 'invisible-25.jpg', 'hillsong-25.jpg', 'blood-price-25.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 57, 'total': 57} 2026-06-20 15:17:31,759 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 0, 'added': 0, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 0, 'errors': [], 'total_scanned': 57, 'cancelled': False, 'scan_type': 'metadata'} 2026-06-20 15:17:35,369 | DEBUG | PIL.Image | Image.py:421 | _import_plugin_for_extension() | Importing JpegImagePlugin ``` Version 0.1.35 Beta completed the scan and displayed results ``` 2026-06-20 15:18:26,603 | INFO | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.35 Beta 2026-06-20 15:18:26,740 | INFO | bulk_image_organizer.main_window | main_window.py:294 | __init__() | MainWindow initialized (PR13 configuration milestone) 2026-06-20 15:18:26,887 | INFO | bulk_image_organizer.main | main.py:98 | main() | Main window shown 2026-06-20 15:18:47,080 | INFO | bulk_image_organizer.main_window | main_window.py:3572 | open_directory() | Preloaded 57 rows from working DB for D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:18:47,084 | INFO | bulk_image_organizer.main_window | main_window.py:3576 | open_directory() | Hydrated 57 cached thumbnails into grid for D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:18:47,097 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:18:47,099 | INFO | bulk_image_organizer.main_window | main_window.py:3679 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:18:47,099 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\StagingArea\Desktop Backgrounds\Good Walpapers 2026-06-20 15:18:47,151 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 57, 'seeded': 57, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['glassworks-bg7-25.jpg', 'hillsong-25.jpg', 'linear-dimensions-25.jpg', 'starbirth2x2560.jpg', 'windowsxp_glass_blue.jpg', 'bloom-25.jpg', 'ferric-rainbow-25.jpg', 'invisible-25.jpg', 'cosmic-forces-25.jpg', 'heliograph-25.jpg', 'golden-egg-closeup-25.jpg', 'Big.jpg', 'fish-skeleton-25.jpg', 'edge-25.jpg', 'starbirth-Cropped.jpg', 'bubbles.jpg', 'fish-head-25.jpg', 'interstellar-25.jpg', 'blood-price-25.jpg', 'Blossom.jpg', 'ley-lines-25.jpg', 'firething-25.jpg', 'amazed1600.jpg', 'bluebird-25.jpg', 'corona-25.jpg', 'somethingblue.jpg', 'gold-dragon-25.jpg', 'glory-25.jpg', 'Cerulean.jpg', 'dreaming-25.jpg', 'corporeal-25.jpg', 'corkscrew-25.jpg', 'once1600.jpg', 'AllienMushroom_v2_fullsize.jpg', 'fluorescence6.jpg', 'fireworks-25.jpg', 'intermission-25.jpg', 'dynamo-25.jpg', 'copperwire-25.jpg', 'Splash.jpg', 'glassworks-25.jpg', 'helping-hands-25.jpg', 'brainwave-25.jpg', 'dreamcatcher-25.jpg', 'innocence-25.jpg', 'lethe-25.jpg', 'light-fantastic-25.jpg', 'hemispheres-25.jpg', 'lichens-25.jpg', 'blue%20sphere_fullsize.jpg', 'drift-25.jpg', 'cobaltdaisy.jpg', 'anen.jpg', 'into-forever-25.jpg', 'blue-outpost-25.jpg', 'hellid-25.jpg', 'Asteroids.jpg'], 'changed_paths': []} 2026-06-20 15:18:47,180 | INFO | bulk_image_organizer.main_window | main_window.py:3806 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['glassworks-bg7-25.jpg', 'hillsong-25.jpg', 'linear-dimensions-25.jpg', 'starbirth2x2560.jpg', 'windowsxp_glass_blue.jpg', 'bloom-25.jpg', 'ferric-rainbow-25.jpg', 'invisible-25.jpg', 'cosmic-forces-25.jpg', 'heliograph-25.jpg', 'golden-egg-closeup-25.jpg', 'Big.jpg', 'fish-skeleton-25.jpg', 'edge-25.jpg', 'starbirth-Cropped.jpg', 'bubbles.jpg', 'fish-head-25.jpg', 'interstellar-25.jpg', 'blood-price-25.jpg', 'Blossom.jpg', 'ley-lines-25.jpg', 'firething-25.jpg', 'amazed1600.jpg', 'bluebird-25.jpg', 'corona-25.jpg', 'somethingblue.jpg', 'gold-dragon-25.jpg', 'glory-25.jpg', 'Cerulean.jpg', 'dreaming-25.jpg', 'corporeal-25.jpg', 'corkscrew-25.jpg', 'once1600.jpg', 'AllienMushroom_v2_fullsize.jpg', 'fluorescence6.jpg', 'fireworks-25.jpg', 'intermission-25.jpg', 'dynamo-25.jpg', 'copperwire-25.jpg', 'Splash.jpg', 'glassworks-25.jpg', 'helping-hands-25.jpg', 'brainwave-25.jpg', 'dreamcatcher-25.jpg', 'innocence-25.jpg', 'lethe-25.jpg', 'light-fantastic-25.jpg', 'hemispheres-25.jpg', 'lichens-25.jpg', 'blue%20sphere_fullsize.jpg', 'drift-25.jpg', 'cobaltdaisy.jpg', 'anen.jpg', 'into-forever-25.jpg', 'blue-outpost-25.jpg', 'hellid-25.jpg', 'Asteroids.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 57, 'total': 57} 2026-06-20 15:18:47,216 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 0, 'added': 0, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 0, 'errors': [], 'total_scanned': 57, 'cancelled': False, 'scan_type': 'metadata'} 2026-06-20 15:18:50,592 | DEBUG | PIL.Image | Image.py:421 | _import_plugin_for_extension() | Importing JpegImagePlugin ```
Member

Thank you for the detailed logs and directory listing — that was exactly what I needed, and I think I found it.

The key clue: in your 0.1.48 log, the very last line is DupeWorker.run() starting, immediately followed by total silence — no progress, no error, nothing. That confirms a true native crash (not a Python exception — my checkpoint logging and the try/except guard from the last round would have caught and logged anything Python-level). In your 0.1.36 log, the crash also happens right after Importing JpegImagePlugin, the first time Pillow loads a JPEG decoder that run — same place, just earlier in that version's lifecycle since fewer thumbnails were cached.

Both of your test runs were an exact scan (kind=exact in the 0.1.48 log — "Scan Duplicate Files" defaults to this). Here's the bug: _compute_hashes() always computed two things for every image, regardless of which scan kind needed them — the sha256 exact hash (pure standard library, no risk) and a perceptual hash via the imagehash library, even on an exact-only scan that never uses it. imagehash pulls in numpy, scipy, and PyWavelets — a much heavier native-dependency chain (BLAS/LAPACK/FFT routines, often with their own vendored DLLs) than plain hashlib. That stack is a well-documented source of exactly this symptom — silent native crashes with no Python traceback — in frozen/Nuitka-style Windows builds, usually from a missing vendored DLL or an unsupported CPU instruction path being selected on first use.

Fix (pushed to the same branch, 0.1.47/issue-111-86-64-89-feedback-fixes, now at 0.1.49): split the hashing so an exact scan never touches imagehash/numpy/scipy at all — only the plain sha256 path runs. A perceptual ("visual") scan still needs the perceptual hash, so if that dependency chain really is the cause, a visual scan might still crash; exact scans should not. Also added per-image checkpoint logging (Hashing 1/57: <file>, etc.) so if anything still goes wrong, the log will show exactly which file it happened on instead of just the start of the loop.

Could you retest from this branch? Specifically:

  1. Try Scan Duplicate Files (exact) again — this is the one I'm now fairly confident is fixed.
  2. If you're willing, also try whatever triggers a visual/perceptual scan in the UI — if that one still crashes, it confirms the imagehash/numpy/scipy theory definitively and tells us we need to replace that dependency rather than just avoid it for exact scans.

Recorded the full reasoning as DR-027 in docs/DECISIONS.md for anyone following along. Leaving this open until you've had a chance to retest.

Thank you for the detailed logs and directory listing — that was exactly what I needed, and I think I found it. **The key clue:** in your 0.1.48 log, the very last line is `DupeWorker.run() starting`, immediately followed by total silence — no progress, no error, nothing. That confirms a true native crash (not a Python exception — my checkpoint logging and the try/except guard from the last round would have caught and logged anything Python-level). In your 0.1.36 log, the crash also happens right after `Importing JpegImagePlugin`, the first time Pillow loads a JPEG decoder that run — same place, just earlier in that version's lifecycle since fewer thumbnails were cached. Both of your test runs were an **exact** scan (`kind=exact` in the 0.1.48 log — "Scan Duplicate Files" defaults to this). Here's the bug: `_compute_hashes()` *always* computed two things for every image, regardless of which scan kind needed them — the sha256 exact hash (pure standard library, no risk) **and** a perceptual hash via the `imagehash` library, even on an exact-only scan that never uses it. `imagehash` pulls in `numpy`, `scipy`, and `PyWavelets` — a much heavier native-dependency chain (BLAS/LAPACK/FFT routines, often with their own vendored DLLs) than plain `hashlib`. That stack is a well-documented source of exactly this symptom — silent native crashes with no Python traceback — in frozen/Nuitka-style Windows builds, usually from a missing vendored DLL or an unsupported CPU instruction path being selected on first use. **Fix (pushed to the same branch, `0.1.47/issue-111-86-64-89-feedback-fixes`, now at 0.1.49):** split the hashing so an exact scan never touches `imagehash`/`numpy`/`scipy` at all — only the plain sha256 path runs. A perceptual ("visual") scan still needs the perceptual hash, so if that dependency chain really is the cause, a *visual* scan might still crash; exact scans should not. Also added per-image checkpoint logging (`Hashing 1/57: <file>`, etc.) so if anything still goes wrong, the log will show exactly which file it happened on instead of just the start of the loop. **Could you retest from this branch?** Specifically: 1. Try **Scan Duplicate Files (exact)** again — this is the one I'm now fairly confident is fixed. 2. If you're willing, also try whatever triggers a **visual/perceptual** scan in the UI — if that one still crashes, it confirms the imagehash/numpy/scipy theory definitively and tells us we need to replace that dependency rather than just avoid it for exact scans. Recorded the full reasoning as DR-027 in `docs/DECISIONS.md` for anyone following along. Leaving this open until you've had a chance to retest.
Member

Scan duplicate files has been fixed. Now we need to track down what changed in the visual duplicate scanner. This did previously work as desired so something has regressed the functionality.

2026-06-21 00:04:44,191 | INFO     | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.50 Beta
2026-06-21 00:04:44,396 | INFO     | bulk_image_organizer.main_window | main_window.py:334 | __init__() | MainWindow initialized (PR13 configuration milestone)
2026-06-21 00:04:44,445 | INFO     | bulk_image_organizer.main | main.py:98 | main() | Main window shown
2026-06-21 00:05:20,266 | INFO     | bulk_image_organizer.main_window | main_window.py:3844 | open_directory() | Preloaded 19 rows from working DB for D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:05:20,282 | INFO     | bulk_image_organizer.main_window | main_window.py:3848 | open_directory() | Hydrated 19 cached thumbnails into grid for D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:05:20,340 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:05:20,356 | INFO     | bulk_image_organizer.main_window | main_window.py:3952 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:05:20,356 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:05:20,372 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 19, 'seeded': 19, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['Space/starbirth2x2560.jpg', 'Nature/somethingblue.jpg', 'Nature/once1600.jpg', 'Abstract/Cerulean.jpg', 'Nature/Splash.jpg', 'Asteroids - Copy.jpg', 'Theme/windowsxp_glass_blue.jpg', 'Nature/fluorescence6_2_1.jpg', 'Nature/anen - Copy.jpg', 'Abstract/Big.jpg', 'blue%20sphere_fullsize.jpg', 'Nature/cobaltdaisy_1.jpg', 'Abstract/Blossom.jpg', 'Space/starbirth-Cropped_1_1_1.jpg', 'Space/AllienMushroom_v2_fullsize_1_1.jpg', 'Theme/amazed1600.jpg', 'Nature/bubbles.jpg', 'Nature/fluorescence6_1_1.jpg', 'Nature/fluorescence6 - Copy_1.jpg'], 'changed_paths': []}
2026-06-21 00:05:20,672 | INFO     | bulk_image_organizer.main_window | main_window.py:4079 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['Space/starbirth2x2560.jpg', 'Nature/somethingblue.jpg', 'Nature/once1600.jpg', 'Abstract/Cerulean.jpg', 'Nature/Splash.jpg', 'Asteroids - Copy.jpg', 'Theme/windowsxp_glass_blue.jpg', 'Nature/fluorescence6_2_1.jpg', 'Nature/anen - Copy.jpg', 'Abstract/Big.jpg', 'blue%20sphere_fullsize.jpg', 'Nature/cobaltdaisy_1.jpg', 'Abstract/Blossom.jpg', 'Space/starbirth-Cropped_1_1_1.jpg', 'Space/AllienMushroom_v2_fullsize_1_1.jpg', 'Theme/amazed1600.jpg', 'Nature/bubbles.jpg', 'Nature/fluorescence6_1_1.jpg', 'Nature/fluorescence6 - Copy_1.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 19, 'total': 19}
2026-06-21 00:05:20,723 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 0, 'added': 0, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 0, 'errors': [], 'total_scanned': 19, 'cancelled': False, 'scan_type': 'metadata'}
2026-06-21 00:05:28,444 | INFO     | bulk_image_organizer.main_window | main_window.py:2503 | _start_dupe_scan() | Dupe scan requested: kind=visual root=D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:05:28,444 | INFO     | bulk_image_organizer.main_window | main_window.py:2526 | _start_dupe_scan() | Dupe scan worker constructed; submitting to thread pool
2026-06-21 00:05:28,444 | INFO     | bulk_image_organizer.main_window | main_window.py:2528 | _start_dupe_scan() | Dupe scan worker submitted
2026-06-21 00:05:28,444 | INFO     | bulk_image_organizer.dupe_worker | dupe_worker.py:60 | run() | DupeWorker.run() starting: kind=visual root=D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:05:28,480 | INFO     | bulk_image_organizer.dupe_worker | dupe_worker.py:63 | run() | DupeWorker.run() finished: {'scan_kind': 'visual', 'groups_found': 1, 'groups_skipped': 0, 'tags_created': 1, 'images_tagged': 3, 'hashes_computed': 0, 'errors': [], 'cancelled': False}
2026-06-21 00:05:51,750 | INFO     | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.50 Beta
2026-06-21 00:05:51,959 | INFO     | bulk_image_organizer.main_window | main_window.py:334 | __init__() | MainWindow initialized (PR13 configuration milestone)
2026-06-21 00:05:52,000 | INFO     | bulk_image_organizer.main | main.py:98 | main() | Main window shown
2026-06-21 00:06:12,499 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:06:12,499 | INFO     | bulk_image_organizer.main_window | main_window.py:3952 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:06:12,499 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:06:12,515 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 19, 'seeded': 19, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['Abstract/Blossom.jpg', 'Nature/fluorescence6_2_1.jpg', 'Nature/once1600.jpg', 'Asteroids - Copy.jpg', 'Nature/fluorescence6 - Copy_1.jpg', 'Nature/fluorescence6_1_1.jpg', 'Nature/Splash.jpg', 'Abstract/Big.jpg', 'Nature/somethingblue.jpg', 'blue%20sphere_fullsize.jpg', 'Space/AllienMushroom_v2_fullsize_1_1.jpg', 'Space/starbirth2x2560.jpg', 'Abstract/Cerulean.jpg', 'Nature/bubbles.jpg', 'Nature/cobaltdaisy_1.jpg', 'Theme/amazed1600.jpg', 'Nature/anen - Copy.jpg', 'Theme/windowsxp_glass_blue.jpg', 'Space/starbirth-Cropped_1_1_1.jpg'], 'changed_paths': []}
2026-06-21 00:06:12,515 | INFO     | bulk_image_organizer.main_window | main_window.py:4079 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['Abstract/Blossom.jpg', 'Nature/fluorescence6_2_1.jpg', 'Nature/once1600.jpg', 'Asteroids - Copy.jpg', 'Nature/fluorescence6 - Copy_1.jpg', 'Nature/fluorescence6_1_1.jpg', 'Nature/Splash.jpg', 'Abstract/Big.jpg', 'Nature/somethingblue.jpg', 'blue%20sphere_fullsize.jpg', 'Space/AllienMushroom_v2_fullsize_1_1.jpg', 'Space/starbirth2x2560.jpg', 'Abstract/Cerulean.jpg', 'Nature/bubbles.jpg', 'Nature/cobaltdaisy_1.jpg', 'Theme/amazed1600.jpg', 'Nature/anen - Copy.jpg', 'Theme/windowsxp_glass_blue.jpg', 'Space/starbirth-Cropped_1_1_1.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 19, 'total': 19}
2026-06-21 00:06:12,559 | DEBUG    | PIL.Image | Image.py:421 | _import_plugin_for_extension() | Importing JpegImagePlugin
2026-06-21 00:06:13,200 | INFO     | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 19, 'added': 19, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 19, 'errors': [], 'total_scanned': 19, 'cancelled': False, 'scan_type': 'metadata'}
2026-06-21 00:06:19,631 | INFO     | bulk_image_organizer.main_window | main_window.py:2503 | _start_dupe_scan() | Dupe scan requested: kind=visual root=D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:06:19,631 | INFO     | bulk_image_organizer.main_window | main_window.py:2526 | _start_dupe_scan() | Dupe scan worker constructed; submitting to thread pool
2026-06-21 00:06:19,631 | INFO     | bulk_image_organizer.main_window | main_window.py:2528 | _start_dupe_scan() | Dupe scan worker submitted
2026-06-21 00:06:19,631 | INFO     | bulk_image_organizer.dupe_worker | dupe_worker.py:60 | run() | DupeWorker.run() starting: kind=visual root=D:\Pictures\Desktop Backgrounds\Good Walpapers
2026-06-21 00:06:19,646 | INFO     | bulk_image_organizer.dupe_worker | dupe_worker.py:102 | _run_scan() | Hashing 1/19: Space/AllienMushroom_v2_fullsize_1_1.jpg (need_exact=False, need_visual=True)
PS D:\Pictures\Desktop Backgrounds\Good Walpapers> dir -r
    Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         6/18/2026   4:52 PM                Abstract
d-----         6/18/2026   4:53 PM                Nature
d-----         6/18/2026   4:53 PM                Space
d-----         6/18/2026   4:53 PM                Theme
-a----         6/21/2026  12:06 AM         319488 .bulk_image_organizer.db
-a----          9/1/2004  10:12 PM        1081001 Asteroids - Copy.jpg
-a----         8/28/2003  10:07 PM         789861 blue%20sphere_fullsize.jpg
    Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers\Abstract
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        10/22/2003   4:31 AM         583532 Big.jpg
-a----         8/28/2003  10:07 PM         557103 Blossom.jpg
-a----         7/10/2004   5:37 PM         253635 Cerulean.jpg
    Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers\Nature
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         8/28/2003   9:22 PM         792937 anen - Copy.jpg
-a----         3/13/2004   1:46 PM          70141 bubbles.jpg
-a----         2/26/2003   7:15 PM         302291 cobaltdaisy_1.jpg
-a----         2/26/2003   7:13 PM         168706 fluorescence6 - Copy_1.jpg
-a----         2/26/2003   7:13 PM         168706 fluorescence6_1_1.jpg
-a----         2/26/2003   7:13 PM         168706 fluorescence6_2_1.jpg
-a----          9/1/2004   9:20 PM         817499 once1600.jpg
-a----         2/26/2003   7:14 PM         428949 somethingblue.jpg
-a----        10/15/2006  10:03 PM         104867 Splash.jpg
    Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers\Space
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         8/28/2003   9:23 PM         205685 AllienMushroom_v2_fullsize_1_1.jpg
-a----          8/6/2006  12:15 AM         125367 starbirth-Cropped_1_1_1.jpg
-a----          9/1/2004  10:12 PM         410437 starbirth2x2560.jpg
    Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers\Theme

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----          9/1/2004   9:30 PM         938002 amazed1600.jpg
-a----          7/5/2003   1:10 AM         268090 windowsxp_glass_blue.jpg
Scan duplicate files has been fixed. Now we need to track down what changed in the visual duplicate scanner. This did previously work as desired so something has regressed the functionality. ``` 2026-06-21 00:04:44,191 | INFO | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.50 Beta 2026-06-21 00:04:44,396 | INFO | bulk_image_organizer.main_window | main_window.py:334 | __init__() | MainWindow initialized (PR13 configuration milestone) 2026-06-21 00:04:44,445 | INFO | bulk_image_organizer.main | main.py:98 | main() | Main window shown 2026-06-21 00:05:20,266 | INFO | bulk_image_organizer.main_window | main_window.py:3844 | open_directory() | Preloaded 19 rows from working DB for D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:05:20,282 | INFO | bulk_image_organizer.main_window | main_window.py:3848 | open_directory() | Hydrated 19 cached thumbnails into grid for D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:05:20,340 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:05:20,356 | INFO | bulk_image_organizer.main_window | main_window.py:3952 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:05:20,356 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:05:20,372 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 19, 'seeded': 19, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['Space/starbirth2x2560.jpg', 'Nature/somethingblue.jpg', 'Nature/once1600.jpg', 'Abstract/Cerulean.jpg', 'Nature/Splash.jpg', 'Asteroids - Copy.jpg', 'Theme/windowsxp_glass_blue.jpg', 'Nature/fluorescence6_2_1.jpg', 'Nature/anen - Copy.jpg', 'Abstract/Big.jpg', 'blue%20sphere_fullsize.jpg', 'Nature/cobaltdaisy_1.jpg', 'Abstract/Blossom.jpg', 'Space/starbirth-Cropped_1_1_1.jpg', 'Space/AllienMushroom_v2_fullsize_1_1.jpg', 'Theme/amazed1600.jpg', 'Nature/bubbles.jpg', 'Nature/fluorescence6_1_1.jpg', 'Nature/fluorescence6 - Copy_1.jpg'], 'changed_paths': []} 2026-06-21 00:05:20,672 | INFO | bulk_image_organizer.main_window | main_window.py:4079 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['Space/starbirth2x2560.jpg', 'Nature/somethingblue.jpg', 'Nature/once1600.jpg', 'Abstract/Cerulean.jpg', 'Nature/Splash.jpg', 'Asteroids - Copy.jpg', 'Theme/windowsxp_glass_blue.jpg', 'Nature/fluorescence6_2_1.jpg', 'Nature/anen - Copy.jpg', 'Abstract/Big.jpg', 'blue%20sphere_fullsize.jpg', 'Nature/cobaltdaisy_1.jpg', 'Abstract/Blossom.jpg', 'Space/starbirth-Cropped_1_1_1.jpg', 'Space/AllienMushroom_v2_fullsize_1_1.jpg', 'Theme/amazed1600.jpg', 'Nature/bubbles.jpg', 'Nature/fluorescence6_1_1.jpg', 'Nature/fluorescence6 - Copy_1.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 19, 'total': 19} 2026-06-21 00:05:20,723 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 0, 'added': 0, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 0, 'errors': [], 'total_scanned': 19, 'cancelled': False, 'scan_type': 'metadata'} 2026-06-21 00:05:28,444 | INFO | bulk_image_organizer.main_window | main_window.py:2503 | _start_dupe_scan() | Dupe scan requested: kind=visual root=D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:05:28,444 | INFO | bulk_image_organizer.main_window | main_window.py:2526 | _start_dupe_scan() | Dupe scan worker constructed; submitting to thread pool 2026-06-21 00:05:28,444 | INFO | bulk_image_organizer.main_window | main_window.py:2528 | _start_dupe_scan() | Dupe scan worker submitted 2026-06-21 00:05:28,444 | INFO | bulk_image_organizer.dupe_worker | dupe_worker.py:60 | run() | DupeWorker.run() starting: kind=visual root=D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:05:28,480 | INFO | bulk_image_organizer.dupe_worker | dupe_worker.py:63 | run() | DupeWorker.run() finished: {'scan_kind': 'visual', 'groups_found': 1, 'groups_skipped': 0, 'tags_created': 1, 'images_tagged': 3, 'hashes_computed': 0, 'errors': [], 'cancelled': False} 2026-06-21 00:05:51,750 | INFO | bulk_image_organizer.main | main.py:79 | main() | Starting Bulk Image Organizer 0.1.50 Beta 2026-06-21 00:05:51,959 | INFO | bulk_image_organizer.main_window | main_window.py:334 | __init__() | MainWindow initialized (PR13 configuration milestone) 2026-06-21 00:05:52,000 | INFO | bulk_image_organizer.main | main.py:98 | main() | Main window shown 2026-06-21 00:06:12,499 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background discovery scan of D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:06:12,499 | INFO | bulk_image_organizer.main_window | main_window.py:3952 | _launch_directory_scan() | Launched placeholder+deep ScanWorkers for root=D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:06:12,499 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:98 | run() | Starting background metadata scan of D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:06:12,515 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'total': 19, 'seeded': 19, 'errors': [], 'cancelled': False, 'scan_type': 'placeholders', 'all_paths': ['Abstract/Blossom.jpg', 'Nature/fluorescence6_2_1.jpg', 'Nature/once1600.jpg', 'Asteroids - Copy.jpg', 'Nature/fluorescence6 - Copy_1.jpg', 'Nature/fluorescence6_1_1.jpg', 'Nature/Splash.jpg', 'Abstract/Big.jpg', 'Nature/somethingblue.jpg', 'blue%20sphere_fullsize.jpg', 'Space/AllienMushroom_v2_fullsize_1_1.jpg', 'Space/starbirth2x2560.jpg', 'Abstract/Cerulean.jpg', 'Nature/bubbles.jpg', 'Nature/cobaltdaisy_1.jpg', 'Theme/amazed1600.jpg', 'Nature/anen - Copy.jpg', 'Theme/windowsxp_glass_blue.jpg', 'Space/starbirth-Cropped_1_1_1.jpg'], 'changed_paths': []} 2026-06-21 00:06:12,515 | INFO | bulk_image_organizer.main_window | main_window.py:4079 | _on_placeholder_finished() | Placeholder scan complete: {'all_paths': ['Abstract/Blossom.jpg', 'Nature/fluorescence6_2_1.jpg', 'Nature/once1600.jpg', 'Asteroids - Copy.jpg', 'Nature/fluorescence6 - Copy_1.jpg', 'Nature/fluorescence6_1_1.jpg', 'Nature/Splash.jpg', 'Abstract/Big.jpg', 'Nature/somethingblue.jpg', 'blue%20sphere_fullsize.jpg', 'Space/AllienMushroom_v2_fullsize_1_1.jpg', 'Space/starbirth2x2560.jpg', 'Abstract/Cerulean.jpg', 'Nature/bubbles.jpg', 'Nature/cobaltdaisy_1.jpg', 'Theme/amazed1600.jpg', 'Nature/anen - Copy.jpg', 'Theme/windowsxp_glass_blue.jpg', 'Space/starbirth-Cropped_1_1_1.jpg'], 'cancelled': False, 'changed_paths': [], 'errors': [], 'scan_type': 'placeholders', 'seeded': 19, 'total': 19} 2026-06-21 00:06:12,559 | DEBUG | PIL.Image | Image.py:421 | _import_plugin_for_extension() | Importing JpegImagePlugin 2026-06-21 00:06:13,200 | INFO | bulk_image_organizer.scan_worker | scan_worker.py:168 | run() | Scan complete: {'processed': 19, 'added': 19, 'pruned': 0, 'pruned_paths': [], 'skipped': 0, 'thumbnails_generated': 19, 'errors': [], 'total_scanned': 19, 'cancelled': False, 'scan_type': 'metadata'} 2026-06-21 00:06:19,631 | INFO | bulk_image_organizer.main_window | main_window.py:2503 | _start_dupe_scan() | Dupe scan requested: kind=visual root=D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:06:19,631 | INFO | bulk_image_organizer.main_window | main_window.py:2526 | _start_dupe_scan() | Dupe scan worker constructed; submitting to thread pool 2026-06-21 00:06:19,631 | INFO | bulk_image_organizer.main_window | main_window.py:2528 | _start_dupe_scan() | Dupe scan worker submitted 2026-06-21 00:06:19,631 | INFO | bulk_image_organizer.dupe_worker | dupe_worker.py:60 | run() | DupeWorker.run() starting: kind=visual root=D:\Pictures\Desktop Backgrounds\Good Walpapers 2026-06-21 00:06:19,646 | INFO | bulk_image_organizer.dupe_worker | dupe_worker.py:102 | _run_scan() | Hashing 1/19: Space/AllienMushroom_v2_fullsize_1_1.jpg (need_exact=False, need_visual=True) ``` ``` PS D:\Pictures\Desktop Backgrounds\Good Walpapers> dir -r Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 6/18/2026 4:52 PM Abstract d----- 6/18/2026 4:53 PM Nature d----- 6/18/2026 4:53 PM Space d----- 6/18/2026 4:53 PM Theme -a---- 6/21/2026 12:06 AM 319488 .bulk_image_organizer.db -a---- 9/1/2004 10:12 PM 1081001 Asteroids - Copy.jpg -a---- 8/28/2003 10:07 PM 789861 blue%20sphere_fullsize.jpg Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers\Abstract Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 10/22/2003 4:31 AM 583532 Big.jpg -a---- 8/28/2003 10:07 PM 557103 Blossom.jpg -a---- 7/10/2004 5:37 PM 253635 Cerulean.jpg Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers\Nature Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 8/28/2003 9:22 PM 792937 anen - Copy.jpg -a---- 3/13/2004 1:46 PM 70141 bubbles.jpg -a---- 2/26/2003 7:15 PM 302291 cobaltdaisy_1.jpg -a---- 2/26/2003 7:13 PM 168706 fluorescence6 - Copy_1.jpg -a---- 2/26/2003 7:13 PM 168706 fluorescence6_1_1.jpg -a---- 2/26/2003 7:13 PM 168706 fluorescence6_2_1.jpg -a---- 9/1/2004 9:20 PM 817499 once1600.jpg -a---- 2/26/2003 7:14 PM 428949 somethingblue.jpg -a---- 10/15/2006 10:03 PM 104867 Splash.jpg Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers\Space Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 8/28/2003 9:23 PM 205685 AllienMushroom_v2_fullsize_1_1.jpg -a---- 8/6/2006 12:15 AM 125367 starbirth-Cropped_1_1_1.jpg -a---- 9/1/2004 10:12 PM 410437 starbirth2x2560.jpg Directory: D:\Pictures\Desktop Backgrounds\Good Walpapers\Theme Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 9/1/2004 9:30 PM 938002 amazed1600.jpg -a---- 7/5/2003 1:10 AM 268090 windowsxp_glass_blue.jpg ```
Member

That log confirmed it precisely — thank you for testing both scan kinds. Pushed the fix to the same branch (0.1.47/issue-111-86-64-89-feedback-fixes, now at 0.1.51).

The last line of your visual-scan log, Hashing 1/19: ... (need_visual=True) followed by total silence, pinpointed the crash to the very first perceptual-hash computation — confirming DR-027's open suspicion. I read imagehash's own source: phash() does import scipy.fftpack lazily, inside its own function body, not when the module loads. That's exactly why everything else in the app (including the parts of imagehash used elsewhere for comparing hashes, which are numpy-only) works fine, while the first call to phash() specifically is what crashes — that's the first and only moment scipy.fftpack actually gets imported and exercised.

Fix: added core/perceptual_hash.py::phash() — a hand-rolled 2D DCT (the same math scipy.fftpack.dct does) using only numpy, which is already used safely elsewhere in this app. It never imports scipy anywhere. I verified it produces bit-for-bit identical hashes to the real imagehash.phash() across 10 random images, 5 different sizes/color modes, and an alpha-channel case — so this isn't a "close enough" approximation, and no existing cached hashes in your workspace are invalidated by the swap. Also confirmed it works correctly with scipy forced unimportable.

Recorded as DR-028 in docs/DECISIONS.md. Could you retest the visual scan once more from this branch? At this point both exact and visual scans should be clear of the dependency that was crashing them — but I'd like your confirmation on the real Windows build before calling this fully resolved.

(Also, noticed your directory got reorganized into subfolders with renamed files between test runs — not an issue, just confirms the new files correctly triggered a fresh perceptual-hash computation rather than reusing a stale cached value, which is what let this surface again.)

That log confirmed it precisely — thank you for testing both scan kinds. Pushed the fix to the same branch (`0.1.47/issue-111-86-64-89-feedback-fixes`, now at 0.1.51). The last line of your visual-scan log, `Hashing 1/19: ... (need_visual=True)` followed by total silence, pinpointed the crash to the very first perceptual-hash computation — confirming DR-027's open suspicion. I read `imagehash`'s own source: `phash()` does `import scipy.fftpack` **lazily, inside its own function body**, not when the module loads. That's exactly why everything else in the app (including the parts of `imagehash` used elsewhere for comparing hashes, which are numpy-only) works fine, while the *first call* to `phash()` specifically is what crashes — that's the first and only moment `scipy.fftpack` actually gets imported and exercised. Fix: added `core/perceptual_hash.py::phash()` — a hand-rolled 2D DCT (the same math `scipy.fftpack.dct` does) using only `numpy`, which is already used safely elsewhere in this app. It never imports `scipy` anywhere. I verified it produces **bit-for-bit identical hashes** to the real `imagehash.phash()` across 10 random images, 5 different sizes/color modes, and an alpha-channel case — so this isn't a "close enough" approximation, and no existing cached hashes in your workspace are invalidated by the swap. Also confirmed it works correctly with `scipy` forced unimportable. Recorded as DR-028 in `docs/DECISIONS.md`. Could you retest the visual scan once more from this branch? At this point both exact and visual scans should be clear of the dependency that was crashing them — but I'd like your confirmation on the real Windows build before calling this fully resolved. (Also, noticed your directory got reorganized into subfolders with renamed files between test runs — not an issue, just confirms the new files correctly triggered a fresh perceptual-hash computation rather than reusing a stale cached value, which is what let this surface again.)
Member

Closing per confirmation that this is resolved. Recap of the full root cause for the record: the crash was always a native (non-Python-catchable) crash inside imagehash.phash()'s lazy import scipy.fftpack, which only fires the first time a perceptual hash is computed in a given run. It surfaced two ways depending on scan kind:

  • Exact scans were calling imagehash.phash() unconditionally even though they never needed it — fixed in 0.1.49 by only computing the hash type each scan kind actually needs (DR-027).
  • Visual/perceptual scans genuinely need the perceptual hash, so they kept crashing until 0.1.51 replaced imagehash.phash()'s computation with a hand-rolled, scipy-free 2D DCT reimplementation in core/perceptual_hash.py, verified bit-identical to the original (DR-028) — so no existing cached hashes were invalidated by the swap.

Thank you for the very precise crash logs across multiple versions and scan kinds — that's what made it possible to localize this without direct access to a Windows machine. Reopen if it resurfaces.

Closing per confirmation that this is resolved. Recap of the full root cause for the record: the crash was always a native (non-Python-catchable) crash inside `imagehash.phash()`'s lazy `import scipy.fftpack`, which only fires the first time a perceptual hash is computed in a given run. It surfaced two ways depending on scan kind: - **Exact scans** were calling `imagehash.phash()` unconditionally even though they never needed it — fixed in 0.1.49 by only computing the hash type each scan kind actually needs (DR-027). - **Visual/perceptual scans** genuinely need the perceptual hash, so they kept crashing until 0.1.51 replaced `imagehash.phash()`'s computation with a hand-rolled, scipy-free 2D DCT reimplementation in `core/perceptual_hash.py`, verified bit-identical to the original (DR-028) — so no existing cached hashes were invalidated by the swap. Thank you for the very precise crash logs across multiple versions and scan kinds — that's what made it possible to localize this without direct access to a Windows machine. Reopen if it resurfaces.
Sign in to join this conversation.
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ai-collab/bulk-image-organizer#111
No description provided.