immich-cli does not properly upload sidecar file (XMP) #4682

Closed
opened 2026-02-05 10:47:17 +03:00 by OVERLORD · 3 comments
Owner

Originally created by @Sinisan1972 on GitHub (Nov 3, 2024).

The bug

Strange things regarding XMP files : there is a bug somewhere.

  1. I have a .HEIC image that has an XMP file that corrects its date. The 2 files have the same name, the extension makes the difference.
  2. I import the folder containing these 2 files via immich-cli. The result is as follows:
    Crawling for assets...
    Checking files | ████████████████████████████████████████ | 100% | ETA: 0s | 1/1 assets
    Found 1 new files and 0 duplicates
    Uploading assets | ████████████████████████████████████████ | 100% | ETA: 0s | 2,6 MB/2,6 MB
    Successfully uploaded 1 new asset (2,6 MB)
  3. I'm pleased to see that the photo has been imported correctly, and that it's stored correctly on the date ‘corrected’ by the XMP file. If I display the photo information, I can also see that the date is indeed the one given by the XMP. So everything's OK so far!
  4. Just to check, without changing anything, I look in the immich "upload" library and see 2 files: the image in .heic format in one folder, and the xmp file in another folder. BUT the two files don't have the same name: these 2 files have a name created by immich that has nothing to do with the original name, but nothing to do with each other either; this obviously doesn't matter as the link between the 2 is taken into account by Immich, probably via its database.

At this stage everything's fine.

BUT from then on :

  • if I run the ‘sync sidecar metadata’ task, the photo is displayed thru immich interface no longer with the date from the XMP imported with the photo, but with its original date.
  • if I then modify the date ‘by hand’ from the Immich web information panel, a new XMP file is created in the same folder as the HEIC image. The name of this file is exactly the name of the photo, including the extension, but with an additional XMP extension (for the photo EXEMPLE.HEIC, the file created is EXEMPLE.HEIC.XMP).
  • if I delete the photo in the interface (and empty the recycle bin, of course), the 2 files are deleted (EXEMPLE.HEIC and EXEMPLE.HEIC.XMP), but the original XMP file created at the time of import remains in place in the other folder, presumably orphaned and never cleaned up by Immich.

The OS that Immich Server is running on

DSM 7.2.1-69057 Update 5

Version of Immich Server

v1.120.1

Version of Immich Mobile App

(don't use)

Platform with the issue

  • Server
  • Web
  • Mobile

Your docker-compose.yml content

#
# WARNING: Make sure to use the docker-compose.yml of the current release:
#
# https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
#
# The compose file on main may not be compatible with the latest release.
#

name: immich

services:
  immich-server:
    container_name: immich_server
    image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
    # extends:
    #   file: hwaccel.transcoding.yml
    #   service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
    volumes:
      # Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
      - ${UPLOAD_LOCATION}:/usr/src/app/upload
      - /etc/localtime:/etc/localtime:ro
    env_file:
      - .env
    ports:
      - '2283:2283'
    depends_on:
      - redis
      - database
    restart: always
    healthcheck:
      disable: false

  immich-machine-learning:
    container_name: immich_machine_learning
    # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag.
    # Example tag: ${IMMICH_VERSION:-release}-cuda
    image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
    # extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
    #   file: hwaccel.ml.yml
    #   service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable
    volumes:
# RDE
#      - model-cache:/cache
      - ./model-cache:/cache
    env_file:
      - .env
    restart: always
    healthcheck:
      disable: false

  redis:
    container_name: immich_redis
    image: docker.io/redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5
    healthcheck:
      test: redis-cli ping || exit 1
    restart: always

  database:
    container_name: immich_postgres
    image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      POSTGRES_INITDB_ARGS: '--data-checksums'
    volumes:
      # Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
      - ${DB_DATA_LOCATION}:/var/lib/postgresql/data
    healthcheck:
      test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
      interval: 5m
      start_period: 5m
    command:
      [
        'postgres',
        '-c',
        'shared_preload_libraries=vectors.so',
        '-c',
        'search_path="$$user", public, vectors',
        '-c',
        'logging_collector=on',
        '-c',
        'max_wal_size=2GB',
        '-c',
        'shared_buffers=512MB',
        '-c',
        'wal_compression=on',
      ]
    restart: always

# RDE
# volumes:
#  model-cache:

# RDE
  backup:
    container_name: immich_db_dumper
    image: prodrigestivill/postgres-backup-local:14
    restart: always
    env_file:
      - .env
    environment:
      POSTGRES_HOST: database
      POSTGRES_CLUSTER: 'TRUE'
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      SCHEDULE: "@daily"
      POSTGRES_EXTRA_OPTS: '--clean --if-exists'
      BACKUP_DIR: /db_dumps
#      BACKUP_ON_START: 'TRUE'
      TZ: Europe/Paris
    volumes:
      - /zzzzzzzzz:/db_dumps
    depends_on:
      - database

Your .env content

# You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables

# The location where your uploaded files are stored
UPLOAD_LOCATION=/volume1/ll
# The location where your database files are stored
DB_DATA_LOCATION=/volume1/postgres

# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
# TZ=Etc/UTC
TZ=Europe/Paris

# RDE : éventuellement à activer pour une restauration, à laisser désactivé en fonctionnement normal
# DB_SKIP_MIGRATIONS=true

# The Immich version to use. You can pin this to a specific version like "v1.71.0"
IMMICH_VERSION=release

# Connection secret for postgres. You should change it to a random password
# Please use only the characters `A-Za-z0-9`, without special characters or spacesez
DB_PASSWORD=xxx

# The values below this line do not need to be changed
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

Reproduction steps

  1. Using immich-cli or immich-go, import one photo with a XMP sidecar : everything's fine. The photo is dated and displayed in Immich with the date included in the XMP.
  2. Run the ‘sync sidecar metadata’ task : the photo is no longer with the date from the XMP imported with the photo, but with its original date.
  3. Modify the date from the Immich web information panel, have a look in the file structure: a new XMP file is created in the same folder as the HEIC image. The name of this file is exactly the name of the photo, including the extension, but with an additional XMP extension (for the photo EXEMPLE.HEIC, the file created is EXEMPLE.HEIC.XMP).
  4. Delete the photo in the interface (and empty the recycle bin, of course), the 2 files are deleted (EXEMPLE.HEIC and EXEMPLE.HEIC.XMP), but the original XMP file created at the time of import remains in place in the other folder, presumably orphaned and never cleaned up by Immich.

Relevant log output

No response

Additional information

No response

Originally created by @Sinisan1972 on GitHub (Nov 3, 2024). ### The bug Strange things regarding XMP files : there is a bug somewhere. 1. I have a .HEIC image that has an XMP file that corrects its date. The 2 files have the same name, the extension makes the difference. 2. I import the folder containing these 2 files via immich-cli. The result is as follows: Crawling for assets... Checking files | ████████████████████████████████████████ | 100% | ETA: 0s | 1/1 assets Found 1 new files and 0 duplicates Uploading assets | ████████████████████████████████████████ | 100% | ETA: 0s | 2,6 MB/2,6 MB Successfully uploaded 1 new asset (2,6 MB) 3. I'm pleased to see that the photo has been imported correctly, and that it's stored correctly on the date ‘corrected’ by the XMP file. If I display the photo information, I can also see that the date is indeed the one given by the XMP. So everything's OK so far! 4. Just to check, without changing anything, I look in the immich "upload" library and see 2 files: the image in .heic format in one folder, and the xmp file in another folder. BUT the two files don't have the same name: these 2 files have a name created by immich that has nothing to do with the original name, but nothing to do with each other either; this obviously doesn't matter as the link between the 2 is taken into account by Immich, probably via its database. At this stage everything's fine. BUT from then on : - if I run the ‘sync sidecar metadata’ task, the photo is displayed thru immich interface no longer with the date from the XMP imported with the photo, but with its original date. - if I then modify the date ‘by hand’ from the Immich web information panel, a new XMP file is created in the same folder as the HEIC image. The name of this file is exactly the name of the photo, including the extension, but with an additional XMP extension (for the photo EXEMPLE.HEIC, the file created is EXEMPLE.HEIC.XMP). - if I delete the photo in the interface (and empty the recycle bin, of course), the 2 files are deleted (EXEMPLE.HEIC and EXEMPLE.HEIC.XMP), but the original XMP file created at the time of import remains in place in the other folder, presumably orphaned and never cleaned up by Immich. ### The OS that Immich Server is running on DSM 7.2.1-69057 Update 5 ### Version of Immich Server v1.120.1 ### Version of Immich Mobile App (don't use) ### Platform with the issue - [X] Server - [X] Web - [ ] Mobile ### Your docker-compose.yml content ```YAML # # WARNING: Make sure to use the docker-compose.yml of the current release: # # https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml # # The compose file on main may not be compatible with the latest release. # name: immich services: immich-server: container_name: immich_server image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} # extends: # file: hwaccel.transcoding.yml # service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding volumes: # Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file - ${UPLOAD_LOCATION}:/usr/src/app/upload - /etc/localtime:/etc/localtime:ro env_file: - .env ports: - '2283:2283' depends_on: - redis - database restart: always healthcheck: disable: false immich-machine-learning: container_name: immich_machine_learning # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag. # Example tag: ${IMMICH_VERSION:-release}-cuda image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release} # extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration # file: hwaccel.ml.yml # service: cpu # set to one of [armnn, cuda, openvino, openvino-wsl] for accelerated inference - use the `-wsl` version for WSL2 where applicable volumes: # RDE # - model-cache:/cache - ./model-cache:/cache env_file: - .env restart: always healthcheck: disable: false redis: container_name: immich_redis image: docker.io/redis:6.2-alpine@sha256:2ba50e1ac3a0ea17b736ce9db2b0a9f6f8b85d4c27d5f5accc6a416d8f42c6d5 healthcheck: test: redis-cli ping || exit 1 restart: always database: container_name: immich_postgres image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USERNAME} POSTGRES_DB: ${DB_DATABASE_NAME} POSTGRES_INITDB_ARGS: '--data-checksums' volumes: # Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file - ${DB_DATA_LOCATION}:/var/lib/postgresql/data healthcheck: test: pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1 interval: 5m start_period: 5m command: [ 'postgres', '-c', 'shared_preload_libraries=vectors.so', '-c', 'search_path="$$user", public, vectors', '-c', 'logging_collector=on', '-c', 'max_wal_size=2GB', '-c', 'shared_buffers=512MB', '-c', 'wal_compression=on', ] restart: always # RDE # volumes: # model-cache: # RDE backup: container_name: immich_db_dumper image: prodrigestivill/postgres-backup-local:14 restart: always env_file: - .env environment: POSTGRES_HOST: database POSTGRES_CLUSTER: 'TRUE' POSTGRES_USER: ${DB_USERNAME} POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: ${DB_DATABASE_NAME} SCHEDULE: "@daily" POSTGRES_EXTRA_OPTS: '--clean --if-exists' BACKUP_DIR: /db_dumps # BACKUP_ON_START: 'TRUE' TZ: Europe/Paris volumes: - /zzzzzzzzz:/db_dumps depends_on: - database ``` ### Your .env content ```Shell # You can find documentation for all the supported env variables at https://immich.app/docs/install/environment-variables # The location where your uploaded files are stored UPLOAD_LOCATION=/volume1/ll # The location where your database files are stored DB_DATA_LOCATION=/volume1/postgres # To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List # TZ=Etc/UTC TZ=Europe/Paris # RDE : éventuellement à activer pour une restauration, à laisser désactivé en fonctionnement normal # DB_SKIP_MIGRATIONS=true # The Immich version to use. You can pin this to a specific version like "v1.71.0" IMMICH_VERSION=release # Connection secret for postgres. You should change it to a random password # Please use only the characters `A-Za-z0-9`, without special characters or spacesez DB_PASSWORD=xxx # The values below this line do not need to be changed ################################################################################### DB_USERNAME=postgres DB_DATABASE_NAME=immich ``` ### Reproduction steps 1. Using immich-cli or immich-go, import one photo with a XMP sidecar : everything's fine. The photo is dated and displayed in Immich with the date included in the XMP. 2. Run the ‘sync sidecar metadata’ task : the photo is no longer with the date from the XMP imported with the photo, but with its original date. 3. Modify the date from the Immich web information panel, have a look in the file structure: a new XMP file is created in the same folder as the HEIC image. The name of this file is exactly the name of the photo, including the extension, but with an additional XMP extension (for the photo EXEMPLE.HEIC, the file created is EXEMPLE.HEIC.XMP). 4. Delete the photo in the interface (and empty the recycle bin, of course), the 2 files are deleted (EXEMPLE.HEIC and EXEMPLE.HEIC.XMP), but the original XMP file created at the time of import remains in place in the other folder, presumably orphaned and never cleaned up by Immich. ### Relevant log output _No response_ ### Additional information _No response_
OVERLORD added the 🗄️serverdate-timecli labels 2026-02-05 10:47:17 +03:00
Author
Owner

@Sinisan1972 commented on GitHub (Apr 20, 2025):

Is there any news about that ? nobody uses sidecar XMP files ?

@Sinisan1972 commented on GitHub (Apr 20, 2025): Is there any news about that ? nobody uses sidecar XMP files ?
Author
Owner

@zilchulant commented on GitHub (Jun 21, 2025):

I would, but this issue prevents me from importing.
Even if the correct metadata is displayed after importing .jpgxl or .heic images (I use immich-go, which seems to use the CLI in the background), it is changed/deleted after running rule tasks. I can't quite determine which of the rule tasks it is, but I suspect the “sidecar metadata” job.

During a test, I found that the processing of sidecar files works with external libraries and is not changed by rule tasks. For me, however, this leads to another problem: I want to back up my iPhone with Immich and Immich does not recognize duplicates between upload and external libraries. See issue 18359

My goal is to import my iCloud Photo Library into Immich and back up all future pictures from the iPhone to Immich (I use osxphotos to export from the iCloud Photo library). I would like to convert all older pictures (>5 years, for example) as jpgxl (Q=85) to save about 20-40% of the space compared to .heic / .jpg. However, I cannot (yet) read the EXIF data from jpgxl (Issue 5161), so the sidecar files would be very helpful here.
In the next step I will check whether the additional EXIF data in .heic files are also read out completely, are not deleted and the correct date is set.

Update

I carried out further tests and was able to draw the following conclusions:

  • Some of my problems come from the fact that immich-go overwrites the existing tags with the “--session-tag” for many images. Issue: 977
  • Immich can actually extract the metadata from jpgxl. My assumption was wrong

This issue still exists and should receive even more attention

  • Normally, immich imports files associated with an image (sidecar xmp, live video) into their own folder structures with their own names.
  • If images have no metadata, existing metadata is no longer displayed when the sidecar metadata job is executed
  • One fix is to move files associated with the image to the same folder as the image and give them the same name. If you then run the sidecar metadata job, these are displayed again.
@zilchulant commented on GitHub (Jun 21, 2025): I would, but this issue prevents me from importing. Even if the correct metadata is displayed after importing **.jpgxl or .heic images** (I use immich-go, which seems to use the CLI in the background), it is changed/deleted after running rule tasks. I can't quite determine which of the rule tasks it is, but I suspect the **“sidecar metadata”** job. During a test, I found that the processing of sidecar files works with **external libraries** and is not changed by rule tasks. For me, however, this leads to another problem: I want to back up my iPhone with Immich and Immich does not recognize duplicates between upload and external libraries. See issue [18359](https://github.com/immich-app/immich/discussions/18359) My goal is to import my iCloud Photo Library into Immich and back up all future pictures from the iPhone to Immich (I use [osxphotos](https://github.com/RhetTbull/osxphotos) to export from the iCloud Photo library). I would like to convert all older pictures (>5 years, for example) as jpgxl (Q=85) to save about 20-40% of the space compared to .heic / .jpg. However, I cannot (yet) read the EXIF data from jpgxl (Issue [5161](https://github.com/immich-app/immich/issues/5161)), so the sidecar files would be very helpful here. In the next step I will check whether the additional EXIF data in .heic files are also read out completely, are not deleted and the correct date is set. ### Update I carried out further tests and was able to draw the following conclusions: - Some of my problems come from the fact that immich-go overwrites the existing tags with the “--session-tag” for many images. Issue: [977](https://github.com/simulot/immich-go/issues/977) - Immich can actually extract the metadata from jpgxl. My assumption was wrong **This issue still exists and should receive even more attention** - Normally, immich imports files associated with an image (sidecar xmp, live video) into their own folder structures with their own names. - If images have no metadata, existing metadata is no longer displayed when the sidecar metadata job is executed - **One fix** is to move files associated with the image to the same folder as the image and give them the same name. If you then run the sidecar metadata job, these are displayed again.
Author
Owner

@jrasm91 commented on GitHub (Aug 26, 2025):

It looks like there was a bug in the sidecar sync job that would ignore the asset.sidecarPath if it wasn't next to the asset with the same name. This should be fixed with the linked PR though.

@jrasm91 commented on GitHub (Aug 26, 2025): It looks like there was a bug in the sidecar sync job that would ignore the `asset.sidecarPath` if it wasn't next to the asset with the same name. This should be fixed with the linked PR though.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: immich-app/immich#4682