Tags not attached to images
I see tags being created in Immich, however, the uploaded images don't have the tag attached.
Seems to affect --tag "test", --takeout-tag, --people-tag, as well as --session-tag.
./immich-go upload from-google-photos --server=http://immich.fritz.box:2283 --api-key=znamWTd4H6ijpqxbdguSJ6frAvcvjxa6UA1MObE1PhI --skip-verify-ssl --log-file --takeout-tag --people-tag --session-tag --tag "upload-run-3" --from-album-name "Shared test" /Users/max/Documents/google-photos-takeout-2/takeout-*.zip
The logs read like it successfully attached the one image that is part of the "Shared test" album that I was uploading 🤔
│2025-06-30 12:25:50 INF created tag tag=upload-run-3 │
│2025-06-30 12:25:50 INF updated tag tag=upload-run-3 assets=1 │
│2025-06-30 12:25:50 INF created tag tag=takeout-20250629T224043Z │
│2025-06-30 12:25:50 INF updated tag tag=takeout-20250629T224043Z assets=1 │
│2025-06-30 12:25:50 INF created tag tag={immich-go}/2025-06-30 12:25:43 │
│2025-06-30 12:25:50 INF updated tag tag={immich-go}/2025-06-30 12:25:43 assets=1
Am I doing something wrong or did the tagging functionality maybe break recently? 🤔
In the Immich UI, the image detail view doesn't show the tag, the tag detail view doesn't show the image and searching for tags also doesn't return the image.
immich-go: 0.27.0 immich: 1.135.3
PS: I'm trying to migrate from google photos to immich and I think it'd literally be impossible without the help of immich-go. Thanks for building it! ❤
Am I doing something wrong or did the tagging functionality maybe break recently? 🤔
Um... can you run an import with --log-level=DEBUG and --api-trace set... Then share the logs on my discord account @simulot ?
Um... can you run an import with
--log-level=DEBUGand--api-traceset... Then share the logs on my discord account @simulot ?
The important pieces seem to be the following:
Logs:
2025-06-30 16:12:00 INF uploaded file=takeout-20250629T224043Z-1-001:Takeout/Google Fotos/Shared test/IMG_20250618_194917.jpg
2025-06-30 16:12:01 DBG file.FileName=takeout-20250629T224043Z-1-001:Takeout/Google Fotos/Shared test/IMG_20250618_194917.jpg file.FileDate=2025-06-29 22:46:20 file.Description= file.Title=IMG_20250618_194917.jpg file.FileSize=4529672 file.ID=c1608b19-15e6-4887-b65c-0e7c8fda9fcb file.CaptureDate=2025-06-18 19:49:17 file.Trashed=false file.Archived=false file.FromPartner=false file.Favorite=false file.Stars=0 file.Latitude=48.xxxxx file.Longitude=11.xxxxx
2025-06-30 16:12:01 INF added to an album file=takeout-20250629T224043Z-1-001:Takeout/Google Fotos/Shared test/IMG_20250618_194917.jpg album=Shared test
2025-06-30 16:12:01 INF Tagged file=takeout-20250629T224043Z-1-001:Takeout/Google Fotos/Shared test/IMG_20250618_194917.jpg tag={immich-go}/2025-06-30 16:11:52
2025-06-30 16:12:01 INF Tagged file=takeout-20250629T224043Z-1-001:Takeout/Google Fotos/Shared test/IMG_20250618_194917.jpg tag=takeout-20250629T224043Z
2025-06-30 16:12:01 DBG CacheReader: remove temporary file name=/Users/max/Library/Caches/immich-go/temp/immich-go_252115217
2025-06-30 16:12:01 INF created album album=Shared test assets=1
2025-06-30 16:12:01 INF created tag tag={immich-go}/2025-06-30 16:11:52
2025-06-30 16:12:01 INF updated tag tag={immich-go}/2025-06-30 16:11:52 assets=1
2025-06-30 16:12:01 INF created tag tag=takeout-20250629T224043Z
2025-06-30 16:12:01 INF updated tag tag=takeout-20250629T224043Z assets=1
API Traces (show success messages):
2025-06-30T16:12:01+02:00 QUERY 26 UpsertTags PUT http://immich.fritz.box:2283/api/tags
Content-Type [application/json]
Accept [application/json]
X-Api-Key redacted
-- body start --
{"tags":["{immich-go}/2025-06-30 16:11:52"]}
-- body end --
2025-06-30T16:12:01+02:00 RESPONSE 26 UpsertTags PUT http://immich.fritz.box:2283/api/tags
Header:
Connection : keep-alive
Content-Type : application/json; charset=utf-8
Content-Length : 246
Vary : Accept-Encoding
Keep-Alive : timeout=5
X-Powered-By : Express
X-Immich-Cid : fw56ov9e
Etag : "f6-2m/qD6l6DHIyBcenfUN7AsxNNbQ"
Date : Mon, 30 Jun 2025 14:12:01 GMT
Status: 200 OK
-- response body start --
[{"id":"56dfc814-ae2c-482e-93a6-4f472f4225e4","parentId":"80de92ad-6e0e-450c-901c-63035f0202b0","name":"2025-06-30 16:11:52","value":"{immich-go}/2025-06-30 16:11:52","createdAt":"2025-06-30T14:12:01.188Z","updatedAt":"2025-06-30T14:12:01.188Z"}]
-- response body end --
2025-06-30T16:12:01+02:00 QUERY 27 TagAssets PUT http://immich.fritz.box:2283/api/tags/56dfc814-ae2c-482e-93a6-4f472f4225e4/assets
Accept [application/json]
X-Api-Key redacted
Content-Type [application/json]
-- body start --
{"ids":["c1608b19-15e6-4887-b65c-0e7c8fda9fcb"]}
-- body end --
2025-06-30T16:12:01+02:00 RESPONSE 27 TagAssets PUT http://immich.fritz.box:2283/api/tags/56dfc814-ae2c-482e-93a6-4f472f4225e4/assets
Header:
Keep-Alive : timeout=5
X-Immich-Cid : 1g0uoqsh
Etag : "3e-P1Q6kR0nM4Dl+dp0rHjBednjB4I"
Vary : Accept-Encoding
Date : Mon, 30 Jun 2025 14:12:01 GMT
X-Powered-By : Express
Content-Type : application/json; charset=utf-8
Content-Length : 62
Connection : keep-alive
Status: 200 OK
-- response body start --
[{"id":"c1608b19-15e6-4887-b65c-0e7c8fda9fcb","success":true}]
-- response body end --
2025-06-30T16:12:01+02:00 QUERY 28 UpsertTags PUT http://immich.fritz.box:2283/api/tags
Content-Type [application/json]
Accept [application/json]
X-Api-Key redacted
-- body start --
{"tags":["takeout-20250629T224043Z"]}
-- body end --
2025-06-30T16:12:01+02:00 RESPONSE 28 UpsertTags PUT http://immich.fritz.box:2283/api/tags
Header:
X-Powered-By : Express
X-Immich-Cid : 1g0fbf9o
Content-Type : application/json; charset=utf-8
Content-Length : 194
Etag : "c2-HTEKVL2PfOKtoVAq6rwLJ8+9sGg"
Date : Mon, 30 Jun 2025 14:12:01 GMT
Keep-Alive : timeout=5
Vary : Accept-Encoding
Connection : keep-alive
Status: 200 OK
-- response body start --
[{"id":"ad495306-a400-46b1-b2ed-ce1397f69323","name":"takeout-20250629T224043Z","value":"takeout-20250629T224043Z","createdAt":"2025-06-30T14:12:01.230Z","updatedAt":"2025-06-30T14:12:01.230Z"}]
-- response body end --
2025-06-30T16:12:01+02:00 QUERY 29 TagAssets PUT http://immich.fritz.box:2283/api/tags/ad495306-a400-46b1-b2ed-ce1397f69323/assets
Content-Type [application/json]
Accept [application/json]
X-Api-Key redacted
-- body start --
{"ids":["c1608b19-15e6-4887-b65c-0e7c8fda9fcb"]}
-- body end --
2025-06-30T16:12:01+02:00 RESPONSE 29 TagAssets PUT http://immich.fritz.box:2283/api/tags/ad495306-a400-46b1-b2ed-ce1397f69323/assets
Header:
X-Powered-By : Express
X-Immich-Cid : 3ecbas1o
Content-Type : application/json; charset=utf-8
Content-Length : 62
Etag : "3e-P1Q6kR0nM4Dl+dp0rHjBednjB4I"
Connection : keep-alive
Keep-Alive : timeout=5
Vary : Accept-Encoding
Date : Mon, 30 Jun 2025 14:12:01 GMT
Status: 200 OK
-- response body start --
[{"id":"c1608b19-15e6-4887-b65c-0e7c8fda9fcb","success":true}]
-- response body end --
Let me know if this doesn't cover everything you were looking for.
Looks pretty much like the upstream issue (https://github.com/immich-app/immich/issues/16747) you already spotted a few months ago, no? Based on the referenced PRs, immich itself apparently workarounds this issue by using bulkTagAssets instead?
The logs show that the API call to create the tag and assign the tag have done their job...
I have tested the feature with latest immich and immich-go:
Question: are you using the Storage Template feature?
Yep, I'm using a storage template.
Can you see if the job STORAGE TEMPLATE MIGRATION is paused by Immich-go
2025-06-30 18:41:08 INF Immich Job command sent pause=storageTemplateMigration
2025-06-30T18:41:08+02:00 QUERY 6 SendJobCommand PUT http://localhost:2283/api/jobs/storageTemplateMigration
Content-Type [application/json]
X-Api-Key redacted
-- body start --
{"command":"pause","force":true}
-- body end --
2025-06-30T18:41:08+02:00 RESPONSE 6 SendJobCommand PUT http://localhost:2283/api/jobs/storageTemplateMigration
Header:
Content-Length : 135
Etag : "87-m5BapuJRp90X/X1K8Nf2NcLEoZQ"
Vary : Accept-Encoding
Date : Mon, 30 Jun 2025 16:41:08 GMT
Connection : keep-alive
X-Immich-Cid : cvfw0u0s
Content-Type : application/json; charset=utf-8
Keep-Alive : timeout=5
X-Powered-By : Express
Status: 200 OK
-- response body start --
{"jobCounts":{"active":0,"completed":0,"failed":0,"delayed":0,"waiting":0,"paused":0},"queueStatus":{"isActive":false,"isPaused":true}}
-- response body end --
You can set the server's log level to debug as well.
Just tested it with storage templates disabled, then it works.
With storage templates enabled, the traces show that the job is paused and once done, resumed:
2025-06-30T18:54:29+02:00 QUERY 16 SendJobCommand PUT http://immich.fritz.box:2283/api/jobs/storageTemplateMigration
Content-Type [application/json]
X-Api-Key redacted
-- body start --
{"command":"pause","force":true}
-- body end --
2025-06-30T18:54:29+02:00 RESPONSE 16 SendJobCommand PUT http://immich.fritz.box:2283/api/jobs/storageTemplateMigration
Header:
X-Powered-By : Express
Content-Length : 135
Etag : "87-m5BapuJRp90X/X1K8Nf2NcLEoZQ"
Keep-Alive : timeout=5
X-Immich-Cid : xoeqmzhq
Content-Type : application/json; charset=utf-8
Vary : Accept-Encoding
Date : Mon, 30 Jun 2025 16:54:29 GMT
Connection : keep-alive
Status: 200 OK
-- response body start --
{"jobCounts":{"active":0,"completed":0,"failed":0,"delayed":0,"waiting":0,"paused":0},"queueStatus":{"isActive":false,"isPaused":true}}
-- response body end --
...
2025-06-30T18:54:37+02:00 QUERY 42 SendJobCommand PUT http://immich.fritz.box:2283/api/jobs/storageTemplateMigration
Content-Type [application/json]
X-Api-Key redacted
-- body start --
{"command":"resume","force":true}
-- body end --
2025-06-30T18:54:37+02:00 RESPONSE 42 SendJobCommand PUT http://immich.fritz.box:2283/api/jobs/storageTemplateMigration
Header:
Vary : Accept-Encoding
X-Powered-By : Express
Etag : "88-42u5DlZiqvmADg8mjxL2JXvkN5I"
Date : Mon, 30 Jun 2025 16:54:37 GMT
Connection : keep-alive
Keep-Alive : timeout=5
X-Immich-Cid : fad46fe9
Content-Type : application/json; charset=utf-8
Content-Length : 136
Status: 200 OK
-- response body start --
{"jobCounts":{"active":0,"completed":0,"failed":0,"delayed":0,"waiting":0,"paused":0},"queueStatus":{"isActive":false,"isPaused":false}}
-- response body end --
Aren't you able to reproduce it, too, when using storage templates?
Aren't you able to reproduce it, too, when using storage templates?
It will likely fail too. The job pause trick used to work with previous major version of immich
I don't see anything I can do to make immich work. I'd suggest filing an issue with the immich project
I am facing this issue with the tags as well. Meanwhile, I suppose to workaround the issue, I should turn off the storage template engine, perform the upload, then turn the storage template back on and run the Storage Template Migration job?
I'm running into this issue currently even without having Storage Templates on. Assuming my understanding of the underlying issue is correct, would it be possible to add an option to immich-go that creates a standalone script containing all of the API commands that set the tags (maybe with something like --create-tagging-script)? That way we could manually run that after all of the immich jobs are completed. Not sure how feasible or difficult that would be. I'm just spitballing.
Facing this issue as well. @simulot isn't there something we can do even as a workaround while they fix it upstream? Like delaying the update somehow?
I don't fully understand what causes the issue. But I'm stuck not able to upload, and I'm happy to do some manual lifting if that means not losing the proper tags.
If the issue is updating a photo right after uploading, I find it strange that the album assignation works, but the tags don't.
For those of you facing this issue and looking for a temporary workaround.
I have built a patched version with a new option to skip tagging and improve logs to allow for manual tagging via easy API calls. You can find more info a download it here.
Disclaimer: I am no dev. I have no clue of what I'm doing. This was done mostly using AI. This is the first time ever I create a release in Github, and even my own repo. The code might not be perfect. BUT it works.
Is it possible this issue is not only specific to tags?
Doing a few test updates repeatedly and I'm finding the same kind of behaviour for ALL metadata. Result is that photos upload fine, but a few seconds right after, when refreshing the server page, some photos metadata has been wiped. It's easily seen because some photos suddenly move position and show up with today's date instead.
It's inconsistent, sometimes they all keep the data (in my test upload of 4 photos), sometimes a few are retained and a few wiped. It's quite random, which made me instantly think back to this issue with the tags.
And really, since I "think" both cases work using the updateAsset API call, right after upload... this seems strongly related...
Again very surprised no-one has reported this before. Metadata is way more used than tags, and people even more fussy about it.
Facing the same issue, tags are missing, tags are created, but not attached to images
Can any one share more details on, how storage template and tags are related? And what would be possible fix on upstream side? Thn i can file an issue there, and may be see if i can create a PR (I am a dev, but new to immich)
@simulot
I also see, some of following stack traces in server logs
[Nest] 6 - 08/12/2025, 7:00:05 AM WARN [Microservices:Error: File not found - /usr/src/app/upload/upload/4f56e5e0-3ab2-42a4-8cad-209d3d0543ec/59/46/59468239-921b-4a2c-97f5-0a9493a7b16c.jpg.xmp
at ReadTask._ExifToolTask_parser (/usr/src/app/server/node_modules/exiftool-vendored/dist/ExifToolTask.js:76:71)
at ReadTask.parser (/usr/src/app/server/node_modules/exiftool-vendored/dist/ExifToolTask.js:47:167)
at ReadTask._Task_resolve (/usr/src/app/server/node_modules/batch-cluster/dist/Task.js:146:40)
at runNextTicks (node:internal/process/task_queues:65:5)
at listOnTimeout (node:internal/timers:549:9)
at process.processTimers (node:internal/timers:523:7)] Error reading exif data (/usr/src/app/upload/upload/4f56e5e0-3ab2-42a4-8cad-209d3d0543ec/59/46/59468239-921b-4a2c-97f5-0a9493a7b16c.jpg.xmp): Error: File not found - /usr/src/app/upload/upload/4f56e5e0-3ab2-42a4-8cad-209d3d0543ec/59/46/59468239-921b-4a2c-97f5-0a9493a7b16c.jpg.xmp
Is it possible this issue is not only specific to tags?
Doing a few test updates repeatedly and I'm finding the same kind of behaviour for ALL metadata. Result is that photos upload fine, but a few seconds right after, when refreshing the server page, some photos metadata has been wiped. It's easily seen because some photos suddenly move position and show up with today's date instead.
It's inconsistent, sometimes they all keep the data (in my test upload of 4 photos), sometimes a few are retained and a few wiped. It's quite random, which made me instantly think back to this issue with the tags.
And really, since I "think" both cases work using the
updateAssetAPI call, right after upload... this seems strongly related...Again very surprised no-one has reported this before. Metadata is way more used than tags, and people even more fussy about it.
Yep, happened for me too Some of the photoes showed up under "today"
An update for any one facing the issue with lost metadata and lost tags
Immich-go creates assets, and thn fires api updates for metadata and tags
There exist a race condition between metadata extraction job and sidecar write job And its possible for assets to loose metadata and tags
Solutions would be
- Fix upstream, so metadata extraction job wouldnt overwrite the metadata updated through api
- Or update immich-go to send the metadata as part of POST when creating new asset (POST /assets/ supports passing
sidecarFileas part of multipart form data )
More details can be found at
- https://github.com/immich-app/immich/pull/16901
- https://discord.com/channels/979116623879368755/1399462843581071495
- and immich-go channel on immich discord
I've been working on a draft PR that implements a new flag --update-metadata-only, which I used to reprocess all the images from a takeout after the initial import had been affected by the reported issue.
It's clearly a workaround for the upstream bug in Immich, but if anyone is interested, you can find it here
https://github.com/piffio/immich-go/tree/bug/990-tags-not-attached-to-images
If @simulot is interested in adding this functionality, I can turn it into a proper PR
@piffio , yes I do!
For people who do not see images in albums/tags after uploading: please check if they are being matched to trashed images on the server. In particular, you might be affected by the issue described here where background tasks were paused and never unpaused by immich-go, e.g. because you quit the program prematurely once.
I applied a patch similar to @piffio's above , then re-uploaded images. What happened was: immich-go matched them to trashed images on the server (by checksum), so did not upload the image data, but did add tags/albums (because of my patch). However, I did not see them in the tags/albums pages in the UI, because they were still marked as trashed and trashed images are always hidden (which makes sense I guess).
The solution was to unpause the background tasks that clear out the trash backlog, and wait for those jobs to finish. After re-uploading again (using the patched immich-go), I now see my images in the expected tags/albums.
It does raise the question: shouldn't immich-go "un-trash" an image when it matches it during upload? After all, if a user re-uploads it, I think they expect it to be restored.
The latest release fixes the job resuming.
Why immich-go should untrash images? For example, I have lot of junk photos in my takeout. I patiently sort them out, and I would be upset to see them again.
Experiencing the same problem on latest stable (unable to run latest dev due to #1121).
Without digging it further, it does seem to be a race condition of some kind. immich-go's log order indicates it tries to tag before it creates tags, which is odd (and not sure that's what it's doing):
{"time":"2025-10-12T16:02:50.047583-07:00","level":"INFO","msg":"scanned video file","file":"a6700:private/M4ROOT/CLIP/C0092.MP4"}
{"time":"2025-10-12T16:02:50.047642-07:00","level":"INFO","msg":"scanned sidecar file","file":"a6700:private/M4ROOT/CLIP/C0092.xmp"}
{"time":"2025-10-12T16:02:50.047662-07:00","level":"WARN","msg":"useless file","file":"a6700:C0092M01.XML"}
{"time":"2025-10-12T16:02:50.064418-07:00","level":"INFO","msg":"Assets on the server: 1"}
{"time":"2025-10-12T16:02:55.743741-07:00","level":"INFO","msg":"uploaded","file":"a6700:private/M4ROOT/CLIP/C0092.MP4"}
{"time":"2025-10-12T16:02:55.743809-07:00","level":"DEBUG","msg":"","file":{"FileName":"a6700:private/M4ROOT/CLIP/C0092.MP4","FileDate":"2025-09-07T20:24:34-07:00","Description":"","Title":"C0092.MP4","FileSize":201607754,"ID":"e41af9da-862b-4610-917e-e73ac2b549df","CaptureDate":"2025-08-28T23:30:53-07:00","Trashed":false,"Archived":false,"FromPartner":false,"Favorite":false,"Stars":0,"Latitude":"0.xxxxx","Longitude":"0.xxxxx"}}
{"time":"2025-10-12T16:02:55.743881-07:00","level":"INFO","msg":"Tagged","file":"a6700:private/M4ROOT/CLIP/C0092.MP4","tag":"volume/a6700"}
{"time":"2025-10-12T16:02:55.743934-07:00","level":"INFO","msg":"Tagged","file":"a6700:private/M4ROOT/CLIP/C0092.MP4","tag":"{immich-go}/2025-10-12 16:02:50"}
{"time":"2025-10-12T16:02:55.751696-07:00","level":"INFO","msg":"created tag","tag":"{immich-go}/2025-10-12 16:02:50"}
{"time":"2025-10-12T16:02:55.756207-07:00","level":"INFO","msg":"updated tag","tag":"{immich-go}/2025-10-12 16:02:50","assets":1}
{"time":"2025-10-12T16:02:55.762208-07:00","level":"INFO","msg":"created tag","tag":"volume/a6700"}
{"time":"2025-10-12T16:02:55.765913-07:00","level":"INFO","msg":"updated tag","tag":"volume/a6700","assets":1}
I've rerun the same command a few times after hard deleting the file from Immich and deleting the tags, sometimes it gets tagged with both tags, sometimes with one, and sometimes with none of the tags.
I've created a PR with a feature that workarounds the Immich bug by writing tags into a temporary XMP sidecar before uploading, instead of using Immich tag APIs after the upload. This means tags are attached as part of the initial POST asset upload, in the sidecarData multipart, instead of as subsequent calls to Immich's API.
If there's no sidecar, we create one (with just the tags), and if there is one, we losslessly modify its copy, by adding tags to it before sending it to Immich.
See #1131.
I've been working on a draft PR that implements a new flag
--update-metadata-only, which I used to reprocess all the images from a takeout after the initial import had been affected by the reported issue.It's clearly a workaround for the upstream bug in Immich, but if anyone is interested, you can find it here
https://github.com/piffio/immich-go/tree/bug/990-tags-not-attached-to-images
If @simulot is interested in adding this functionality, I can turn it into a proper PR thank you! this fixed what I've had a headache from the past couple days lol
trashed images on the server
Thanks for the idea to check trashed images! I cleared the trash, and now the empty tags stopped appearing after "Extract metadata" job.
Before this, I deleted empty tags with a script like this one - sorry, it's in .NET
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", apiKey);
client.DefaultRequestHeaders.Add("Accept", "application/json");
var tags = JArray.Parse(await client.GetStringAsync($"{serverUrl}/tags"));
foreach (JObject tag in tags)
{
var buckets = JArray.Parse(await client.GetStringAsync($"{serverUrl}/timeline/buckets?tagId={tag["id"]}"));
if (buckets == null || buckets.Count == 0)
await client.DeleteAsync($"{serverUrl}/tags/{tag["id"]}");
}