I
Immich3w ago
Calvin

Unable to run job handler (PersonGenerateThumbnail): Error: Input file is missing

Hi all! Since last week, I started noticing some errors regarding missing input files. It seems to mainly affect jobs such as the thumbnail generator, as well as when trying to download an image. I’m currently running v2.2.0, but I suspect this issue has been present for a while and does not apply to all assets. Observed behavior: When certain jobs run, I see log messages like this: [Nest] 19 - 11/05/2025, 2:34:40 PM ERROR [Microservices:{"id":"a67f978d-8e4a-4d89-9ead-2e7f23788f47"}] Unable to run job handler (PersonGenerateThumbnail): Error: Input file is missing: /photos/library/tessa/2024/2024-09/IMG_1889.HEIC However, when checking the file on disk, the extension is lowercase (.heic) instead of uppercase (.HEIC) as referenced in the logs. What I’ve checked: - Verified that the file exists on the filesystem (with lowercase extension). - Checked the public.assets table in the database — confirmed that the originalPath references the file with capitalized extension. - Noticed that this behavior is inconsistent — some assets use lowercase extensions, while others use uppercase. - All affected assets belong to a single user who uploads exclusively via the iOS mobile app. Potential solutions (looking for guidance): - Rename files on the filesystem to match the paths stored in the database. - Update the originalPath values in the database to match what’s actually on disk. Before applying either fix, I wanted to confirm which approach would be safer, or if there’s a recommended alternative to handle this properly. Environment: - Immich version: v2.2.0 - Upload source: iOS mobile app - Running in Docker Please let me know if you need any other information!
16 Replies
Immich
Immich3w ago
:wave: Hey @Calvin, Thanks for reaching out to us. Please carefully read this message and follow the recommended actions. This will help us be more effective in our support effort and leave more time for building Immich :immich:. References - Container Logs: docker compose logs docs - Container Status: docker ps -a docs - Reverse Proxy: https://immich.app/docs/administration/reverse-proxy - Code Formatting https://support.discord.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline#h_01GY0DAKGXDEHE263BCAYEGFJA Checklist I have... 1. :ballot_box_with_check: verified I'm on the latest release(note that mobile app releases may take some time). 2. :ballot_box_with_check: read applicable release notes. 3. :ballot_box_with_check: reviewed the FAQs for known issues. 4. :ballot_box_with_check: reviewed Github for known issues. 5. :ballot_box_with_check: tried accessing Immich via local ip (without a custom reverse proxy). 6. :ballot_box_with_check: uploaded the relevant information (see below). 7. :ballot_box_with_check: tried an incognito window, disabled extensions, cleared mobile app cache, logged out and back in, different browsers, etc. as applicable (an item can be marked as "complete" by reacting with the appropriate number) Information In order to be able to effectively help you, we need you to provide clear information to show what the problem is. The exact details needed vary per case, but here is a list of things to consider: - Your docker-compose.yml and .env files. - Logs from all the containers and their status (see above). - All the troubleshooting steps you've tried so far. - Any recent changes you've made to Immich or your system. - Details about your system (both software/OS and hardware). - Details about your storage (filesystems, type of disks, output of commands like fdisk -l and df -h). - The version of the Immich server, mobile app, and other relevant pieces. - Any other information that you think might be relevant. Please paste files and logs with proper code formatting, and especially avoid blurry screenshots. Without the right information we can't work out what the problem is. Help us help you ;) If this ticket can be closed you can use the /close command, and re-open it later if needed. Successfully submitted, a tag has been added to inform contributors. :white_check_mark:
Calvin
CalvinOP3w ago
Your docker-compose.yml and .env files., There is no compose, but will append my config below. Logs from all the containers and their status (see above)., I can provide those if they are needed, but I don't think they help with the matter. All the troubleshooting steps you've tried so far., Already mentioned in my initial post Any recent changes you've made to Immich or your system., None really, quite stable for a while now. Details about your system (both software/OS and hardware)., Running on Unraid, Intel Xeon E-2378, 32GB of memory, multiple HDDs and a single SSD. Details about your storage (filesystems, type of disks, output of commands like fdisk -l and df -h)., Single SSD (which stores thumbnails), HDD stores actual library files. All configured as XFS. The version of the Immich server, mobile app, and other relevant pieces., server v2.2.0, app 2.2.2 build.234
<Name>immich-server</Name>
<Repository>ghcr.io/immich-app/immich-server:release</Repository>
<Registry/>
<Network>br0</Network>
<MyIP/>
<Shell>sh</Shell>
<Privileged>false</Privileged>
<Support/>
<Project/>
<Overview/>
<Category/>
<WebUI/>
<TemplateURL/>
<Icon>https://raw.githubusercontent.com/imagegenius/templates/main/unraid/img/immich.png</Icon>
<ExtraParams>--runtime=nvidia</ExtraParams>
<PostArgs/>
<CPUset/>
<DateInstalled>1760358521</DateInstalled>
<DonateText/>
<DonateLink/>
<Requires/>
<Name>immich-server</Name>
<Repository>ghcr.io/immich-app/immich-server:release</Repository>
<Registry/>
<Network>br0</Network>
<MyIP/>
<Shell>sh</Shell>
<Privileged>false</Privileged>
<Support/>
<Project/>
<Overview/>
<Category/>
<WebUI/>
<TemplateURL/>
<Icon>https://raw.githubusercontent.com/imagegenius/templates/main/unraid/img/immich.png</Icon>
<ExtraParams>--runtime=nvidia</ExtraParams>
<PostArgs/>
<CPUset/>
<DateInstalled>1760358521</DateInstalled>
<DonateText/>
<DonateLink/>
<Requires/>
<Config Name="Library" Target="/photos" Default="" Mode="rw" Description="" Type="Path" Display="always" Required="false" Mask="false">/mnt/user/Data/3 Pictures/immich</Config>
<Config Name="Database Host" Target="DB_HOSTNAME" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">immich-postgres</Config>
<Config Name="Database Username" Target="DB_USERNAME" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">USERNAME</Config>
<Config Name="Database Password" Target="DB_PASSWORD" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">PASSWORD</Config>
<Config Name="Database Name" Target="DB_DATABASE_NAME" Default="" Mode="" Description="" Type="Variable"
<Config Name="Library" Target="/photos" Default="" Mode="rw" Description="" Type="Path" Display="always" Required="false" Mask="false">/mnt/user/Data/3 Pictures/immich</Config>
<Config Name="Database Host" Target="DB_HOSTNAME" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">immich-postgres</Config>
<Config Name="Database Username" Target="DB_USERNAME" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">USERNAME</Config>
<Config Name="Database Password" Target="DB_PASSWORD" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">PASSWORD</Config>
<Config Name="Database Name" Target="DB_DATABASE_NAME" Default="" Mode="" Description="" Type="Variable"
Display="always" Required="false" Mask="false">immich</Config>
<Config Name="Database Port" Target="DB_PORT" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">5432</Config>
<Config Name="Redis Host" Target="REDIS_HOSTNAME" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">redis</Config>
<Config Name="Redis Port" Target="REDIS_PORT" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">6379</Config>
<Config Name="Traefik Enable" Target="traefik.enable" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">true</Config>
<Config Name="Traefik Port" Target="traefik.http.services.immich-server.loadbalancer.server.port" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">2283</Config>
<Config Name="Immich Media Location" Target="IMMICH_MEDIA_LOCATION" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">/photos</Config>
<Config Name="Thumbnails" Target="/photos/thumbs" Default="" Mode="rw" Description="" Type="Path" Display="always" Required="false" Mask="false">/mnt/user/appdata/immich/thumbs</Config>
<Config Name="Nvidia" Target="/dev/dri" Default="" Mode="" Description="" Type="Device" Display="always" Required="false" Mask="false">/dev/dri</Config>
<TailscaleStateDir/>
Display="always" Required="false" Mask="false">immich</Config>
<Config Name="Database Port" Target="DB_PORT" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">5432</Config>
<Config Name="Redis Host" Target="REDIS_HOSTNAME" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">redis</Config>
<Config Name="Redis Port" Target="REDIS_PORT" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">6379</Config>
<Config Name="Traefik Enable" Target="traefik.enable" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">true</Config>
<Config Name="Traefik Port" Target="traefik.http.services.immich-server.loadbalancer.server.port" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">2283</Config>
<Config Name="Immich Media Location" Target="IMMICH_MEDIA_LOCATION" Default="" Mode="" Description="" Type="Variable" Display="always" Required="false" Mask="false">/photos</Config>
<Config Name="Thumbnails" Target="/photos/thumbs" Default="" Mode="rw" Description="" Type="Path" Display="always" Required="false" Mask="false">/mnt/user/appdata/immich/thumbs</Config>
<Config Name="Nvidia" Target="/dev/dri" Default="" Mode="" Description="" Type="Device" Display="always" Required="false" Mask="false">/dev/dri</Config>
<TailscaleStateDir/>
Sergey Katsubo
Hey! Looks like you already did solid investigation. 1. Storage template always converts extensions to lowercase: #16667. Storage template first moves actual file on disk, then updates originalPath in the database. To handle possible failures in the middle and avoid inconsistencies db-vs-disk, it keeps a journal in the move_history table and retries operations later. But #16611 introduced clean-up of move_history when Storage Template Migration job is run manually. 2. Are the affected files (with uppercase extensions) still present among recent uploads? How are they distributed over time? You can check for non-lowercase extensions
SELECT "createdAt", "originalPath", "originalFileName" FROM asset WHERE not "isExternal" AND "originalPath" ~ '\.[^.]*[A-Z][^.]*$';
SELECT "createdAt", "originalPath", "originalFileName" FROM asset WHERE not "isExternal" AND "originalPath" ~ '\.[^.]*[A-Z][^.]*$';
(createdAt is timestamp when Immich added an asset record) Or - more general approach - check for mismatch between the database and disk. Smth like https://discord.com/channels/979116623879368755/1427222879593955428/1427305692884373524. E.g.
docker exec immich_postgres psql -U postgres -d immich -At0 -c 'select "originalPath" from asset where not "isExternal" limit 100' | docker exec -i immich_server xargs -0 stat -t -c "%.19y %10s %n" | grep 'cannot statx'
docker exec immich_postgres psql -U postgres -d immich -At0 -c 'select "originalPath" from asset where not "isExternal" limit 100' | docker exec -i immich_server xargs -0 stat -t -c "%.19y %10s %n" | grep 'cannot statx'
3. Do you have anything in move_history? Perhaps re-running Storage Template Migration won't help in your case. I expect it will emit warnings and return without updating records in the database. If I understand correctly this section of code https://github.com/mmomjian/immich/blob/698531d6e00d805ec2a6701e65c9dd8ae8457df3/server/src/cores/storage.core.ts#L217-L220
Immich
Immich3w ago
this.logger.warn(
\`Unable to complete move. Error renaming file with code ${error.code} and message: ${error.message}\`,
);
return;
this.logger.warn(
\`Unable to complete move. Error renaming file with code ${error.code} and message: ${error.message}\`,
);
return;
[Pull Request] feat(server): normalize extensions in storage template (immich-app/immich#16667) [Pull Request] fix: storage template failure after re-upload and previous fail (immich-app/immich#16611)
Sergey Katsubo
As files are already at proper location and with lowercase extension, all that remains is updating originalPath in the database. This is what savePath would do if it had a chance to be executed. I suggest to create a DB backup (or check your nightly backups). Then update mismatched disk-vs-db extensions to lowercase in asset."originalPath".
Immich
Immich3w ago
await this.savePath(pathType, entityId, newPath);
await this.savePath(pathType, entityId, newPath);
Calvin
CalvinOP3w ago
Hi Sergey, Thanks for sharing your insights on the matter. 1. It's good to know that the expected behaviour is that all extensions are getting converted to lowercase. I see that change was merged in march, I can also confirm that the list of assets that are affected, seems to be up to march this year as well.
Calvin
CalvinOP3w ago
2. This is actually a good question: I have updated the query to:
SELECT "createdAt", "originalPath", "originalFileName"
FROM asset
WHERE NOT "isExternal"
AND "originalPath" ~ '\.[^.]*[A-Z][^.]*$'
ORDER BY "createdAt" DESC;
SELECT "createdAt", "originalPath", "originalFileName"
FROM asset
WHERE NOT "isExternal"
AND "originalPath" ~ '\.[^.]*[A-Z][^.]*$'
ORDER BY "createdAt" DESC;
Which results in a output of: -- see image attached-- it seems all assets in the library that still have uppercase is limited till early march (prior to 16667 being merged/released). The query however returned 5363 assets, rather than the 2842 assets I've discovered to experience problems based on the logs emitted by triggering a thumbnail job for all assets. I have also ran:
docker exec immich_postgres psql -U postgres -d immich -At0 -c 'select "originalPath" from asset where not "isExternal" limit 100' | docker exec -i immich_server xargs -0 stat -t -c "%.19y %10s %n" | grep 'cannot statx'
docker exec immich_postgres psql -U postgres -d immich -At0 -c 'select "originalPath" from asset where not "isExternal" limit 100' | docker exec -i immich_server xargs -0 stat -t -c "%.19y %10s %n" | grep 'cannot statx'
But there seems to be no output, I've increased the limit of the first query, and I do indeed get results like:
stat: cannot statx '/photos/library/tessa/2024/2024-09/IMG_2121.MOV': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-09/IMG_2090.MOV': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-09/IMG_2066.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-11/IMG_2623.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-11/IMG_2688.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2022/2022-11/IMG_4350.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2022/2022-09/IMG_2317.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2022/2022-08/IMG_2156.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-09/IMG_2121.MOV': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-09/IMG_2090.MOV': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-09/IMG_2066.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-11/IMG_2623.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2024/2024-11/IMG_2688.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2022/2022-11/IMG_4350.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2022/2022-09/IMG_2317.HEIC': No such file or directory
stat: cannot statx '/photos/library/tessa/2022/2022-08/IMG_2156.HEIC': No such file or directory
No description
Calvin
CalvinOP3w ago
3. Yes, there are entries in my move_history, but it's only a couple in comparison to the total number of assets affected, see (these are all entires):
No description
Calvin
CalvinOP3w ago
| I suggest to create a DB backup (or check your nightly backups). Then update mismatched disk-vs-db extensions to lowercase in asset."originalPath". Is the originalPath the only field that needs to be updated? I also see originalFileName? that one is fine to keep a mismatch? I'm a bit hesitant with changing the fields in the database because I was afraid that files would be referenced in multiple places (different tables and colums) and updating them in 1 place might make the situation worse.
Sergey Katsubo
Regarding originalPath vs originalFileName. The meaning of these two fields diverged over the years of Immich evolution: - originalPath = actual path to the asset file (original image) on disk. It is volatile and may change upon applying storage template. - originalFileName = initial (original, historical) file name of the asset at the source, as passed by client to server during upload. Immich keeps it constant/unmodified. Btw, there is System integrity feature #12293 to detect discrepancies db-vs-disk for internal/native library. (For external libraries there is a regular scan that aligns DB state with what is on disk)
it seems all assets in the library that still have uppercase is limited till early march (prior to 16667 being merged/released).
Good to know. Right, both PRs were merged in March. Perhaps smth went wrong and those files stuck in dangling limbo. But there are quite a lot of them, several thousands...
Is the originalPath the only field that needs to be updated?
AFAIK it's the only place (thanks to DB normalization) Sidecars may need extra handling - if you have sidecars ofc - select from asset where "sidecarPath" is not null
Calvin
CalvinOP3w ago
Thanks for confirming that the orginalPath should be the only location, I'll extract a full list of files on the database tomorrow and see which diffs show up with comparing it to the filesystem, I'll then update the database to match the new paths.
Sidecars may need extra handling - if you have sidecars ofc - select from asset where "sidecarPath" is not null
I checked this, it doesn't seem to return any results, so I think that does mean that this is not relevant.
Btw, there is System integrity feature #12293 to detect discrepancies db-vs-disk for internal/native library. (For external libraries there is a regular scan that aligns DB state with what is on disk)
Is this something that can be used rather than updating the database manually? Where can I find more information about it?
Immich
Immich3w ago
[Issue] System integrity feature (immich-app/immich#12293)
Sergey Katsubo
Currently, library integrity is just vision / outline of a feature to be implemented. There is no more details and no ETA. Sorry for possible confusion; the link / FR was meant to show that the need for integrity checking is acknoledged by the team.
Calvin
CalvinOP2w ago
Thanks for the update Sergey and sorry for the delay on my response, I've been able to spend some time on my setup this morning and it seems I have fixed all my issues . I have done the following for anyone who ever comes across this in the future: 1. I started off by identifying which files had a mismatch, my original logs identifying only 2.8K assets wasn't sufficient, however this helped me to identify:
docker exec immich_postgres psql -U postgres -d immich -At0 -c 'select "originalPath" from asset where not "isExternal" limit 100000' | docker exec -i immich_server xargs -0 stat -t -c "%.19y %10s %n" | grep 'cannot statx'
docker exec immich_postgres psql -U postgres -d immich -At0 -c 'select "originalPath" from asset where not "isExternal" limit 100000' | docker exec -i immich_server xargs -0 stat -t -c "%.19y %10s %n" | grep 'cannot statx'
(make sure the replace the container names if they differ in your setup, like it was in my case) 2. I then used the output of that to create update queries, which would update the "old" to the "new" path, where essentially only the extension gets altered from uppercase to lowercase. 3. Once I've executed the whole bunch of queries (about 6K in total), I re-ran the thumbnail generation job, which seems to no longer throw any errors. I've also verified if the files are matching now, by running the same command as mentioned in step 1, which has returned no files anymore. 4. I did end up with a couple new errors;
[Nest] 19 - 11/08/2025, 12:05:06 PM ERROR [Microservices:{"id":"2317c7bd-cc1b-4231-9b70-6d04eb63e447"}] Unable to run job handler (AssetGenerateThumbnails): Error: VipsJpeg: premature end of JPEG image
[Nest] 19 - 11/08/2025, 12:05:06 PM ERROR [Microservices:{"id":"2317c7bd-cc1b-4231-9b70-6d04eb63e447"}] Unable to run job handler (AssetGenerateThumbnails): Error: VipsJpeg: premature end of JPEG image
which does seem unrelated to my original issue, but I just ran this through convert which fixed the image, after that immich was all happy again. I can now say, my immich is completly back to normal, no errors and functions like it always did. What caused the issue I had, it's still an unknown to me, but I'm glad it's fixed in this manner and I can continue using it. Massive thanks Sergey 🙏 for assisting and providing guidance to resolving this issue!
Immich
Immich2w ago
This thread has been closed. To re-open, use the button below.

Did you find this page helpful?