Replace with upload does not replace #6722

Closed
opened 2026-02-05 12:29:36 +03:00 by OVERLORD · 5 comments
Owner

Originally created by @adzwoolly on GitHub (Aug 3, 2025).

I have searched the existing issues, both open and closed, to make sure this is not a duplicate report.

  • Yes

The bug

Using "replace with upload" does not replace the image or provide any feedback.

The OS that Immich Server is running on

Ubuntu 24.04.2 LTS

Version of Immich Server

v1.137.3

Version of Immich Mobile App

v1.137.2 build.3002

Platform with the issue

  • Server
  • Web
  • Mobile

Your docker-compose.yml content

#
# WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose
#
# 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, rocm, openvino, rknn] 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, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
    volumes:
      - model-cache:/cache
    env_file:
      - .env
    restart: always
    healthcheck:
      disable: false

  redis:
    container_name: immich_redis
    image: docker.io/valkey/valkey:8-bookworm@sha256:ff21bc0f8194dc9c105b769aeabf9585fea6a8ed649c0781caeac5cb3c247884
    healthcheck:
      test: redis-cli ping || exit 1
    restart: always

  database:
    container_name: immich_postgres
    image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0-pgvectors0.2.0@sha256:fa4f6e0971f454cd95fec5a9aaed2ed93d8f46725cc6bc61e0698e97dba96da1
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_DB: ${DB_DATABASE_NAME}
      POSTGRES_INITDB_ARGS: '--data-checksums'
      # Uncomment the DB_STORAGE_TYPE: 'HDD' var if your database isn't stored on SSDs
      # DB_STORAGE_TYPE: 'HDD'
    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
    restart: always

volumes:
  model-cache

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=./library

# The location where your database files are stored. Network shares are not supported for the database
DB_DATA_LOCATION=./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/>
TZ=Europe/London

# 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 spaces
DB_PASSWORD=****************

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

Reproduction steps

  1. View an image (this can be in an album or timeline)
  2. In the options menu, select "replace with upload"
  3. The file picker appears, select a replacement image
  4. Nothing appears to happen, refreshing the page doesn't help.

Relevant log output

No logs in immich_server or browser console

Additional information

Firefox 141.0 (64-bit)

After selecting a replacement image from the local filesystem, a request is made. POST https://domain/api/assets/bulk-upload-check with body {"assets":[{"id":"IMG_9864.jpeg","checksum":"006b0fe90387e57b7656476f7eee564b5b359459"}]}. The image however, isn't replaced.

The original photo is a RAW .dng photo uploaded by a friend via a public link. They sent me a replacement .jpg without any metadata. I was hoping replacing the image would keep the original metadata and use the new image. I also tried renaming the new image from .dng to .jpg

Originally created by @adzwoolly on GitHub (Aug 3, 2025). ### I have searched the existing issues, both open and closed, to make sure this is not a duplicate report. - [x] Yes ### The bug Using "replace with upload" does not replace the image or provide any feedback. ### The OS that Immich Server is running on Ubuntu 24.04.2 LTS ### Version of Immich Server v1.137.3 ### Version of Immich Mobile App v1.137.2 build.3002 ### Platform with the issue - [ ] Server - [x] Web - [ ] Mobile ### Your docker-compose.yml content ```YAML # # WARNING: To install Immich, follow our guide: https://immich.app/docs/install/docker-compose # # 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, rocm, openvino, rknn] 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, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable volumes: - model-cache:/cache env_file: - .env restart: always healthcheck: disable: false redis: container_name: immich_redis image: docker.io/valkey/valkey:8-bookworm@sha256:ff21bc0f8194dc9c105b769aeabf9585fea6a8ed649c0781caeac5cb3c247884 healthcheck: test: redis-cli ping || exit 1 restart: always database: container_name: immich_postgres image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0-pgvectors0.2.0@sha256:fa4f6e0971f454cd95fec5a9aaed2ed93d8f46725cc6bc61e0698e97dba96da1 environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USERNAME} POSTGRES_DB: ${DB_DATABASE_NAME} POSTGRES_INITDB_ARGS: '--data-checksums' # Uncomment the DB_STORAGE_TYPE: 'HDD' var if your database isn't stored on SSDs # DB_STORAGE_TYPE: 'HDD' 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 restart: always volumes: model-cache ``` ### 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=./library # The location where your database files are stored. Network shares are not supported for the database DB_DATA_LOCATION=./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/> TZ=Europe/London # 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 spaces DB_PASSWORD=**************** # The values below this line do not need to be changed ################################################################################### DB_USERNAME=postgres DB_DATABASE_NAME=immich ``` ### Reproduction steps 1. View an image (this can be in an album or timeline) 2. In the options menu, select "replace with upload" 3. The file picker appears, select a replacement image 4. Nothing appears to happen, refreshing the page doesn't help. ### Relevant log output ```shell No logs in immich_server or browser console ``` ### Additional information Firefox 141.0 (64-bit) After selecting a replacement image from the local filesystem, a request is made. POST https://domain/api/assets/bulk-upload-check with body `{"assets":[{"id":"IMG_9864.jpeg","checksum":"006b0fe90387e57b7656476f7eee564b5b359459"}]}`. The image however, isn't replaced. The original photo is a RAW .dng photo uploaded by a friend via a public link. They sent me a replacement .jpg without any metadata. I was hoping replacing the image would keep the original metadata and use the new image. I also tried renaming the new image from .dng to .jpg
Author
Owner

@danieldietzler commented on GitHub (Aug 3, 2025):

There is an open bug with that browsers (and/or reverse proxies) tend to cache thumbnails, and we don't have any way to blow caches currently. Is it possible you're running into that too?

@danieldietzler commented on GitHub (Aug 3, 2025): There is an open bug with that browsers (and/or reverse proxies) tend to cache thumbnails, and we don't have any way to blow caches currently. Is it possible you're running into that too?
Author
Owner

@bo0tzz commented on GitHub (Aug 3, 2025):

Please try with direct access to port 2283, bypassing your reverse proxy and such.

I was hoping replacing the image would keep the original metadata and use the new image.

It won't, it will use the metadata from the .jpg

@bo0tzz commented on GitHub (Aug 3, 2025): Please try with direct access to port 2283, bypassing your reverse proxy and such. > I was hoping replacing the image would keep the original metadata and use the new image. It won't, it will use the metadata from the .jpg
Author
Owner

@adzwoolly commented on GitHub (Aug 3, 2025):

Ah yes, I forgot to mention the reverse proxy.

Accessing the server and port directly performs a different request but, still doesn't appear to update the image.
PUT http://192.168.1.125:2283/api/assets/bdf7f148-c0d5-45f4-858d-1be1d38f5edb/original with a body that has some image data and what I presume is binary data of the image itself.

immich_server now has an error in the logs:

Query failed : {
  durationMs: 7.740293994545937,
  error: PostgresError: duplicate key value violates unique constraint "UQ_assets_owner_checksum"
      at ErrorResponse (/usr/src/app/server/node_modules/postgres/cjs/src/connection.js:794:26)
      at handle (/usr/src/app/server/node_modules/postgres/cjs/src/connection.js:480:6)
      at Socket.data (/usr/src/app/server/node_modules/postgres/cjs/src/connection.js:315:9)
      at Socket.emit (node:events:518:28)
      at addChunk (node:internal/streams/readable:561:12)
      at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
      at Readable.push (node:internal/streams/readable:392:5)
      at TCP.onStreamRead (node:internal/stream_base_commons:189:23)
      at TCP.callbackTrampoline (node:internal/async_hooks:130:17) {
    severity_local: 'ERROR',
    severity: 'ERROR',
    code: '23505',
    detail: 'Key ("ownerId", checksum)=(6776bd1f-4f7a-420e-ae4a-1e41cd23c5a4, \\x006b0fe90387e57b7656476f7eee564b5b359459) already exists.',
    schema_name: 'public',
    table_name: 'asset',
    constraint_name: 'UQ_assets_owner_checksum',
    file: 'nbtinsert.c',
    line: '663',
    routine: '_bt_check_unique'
  },
  sql: `with "asset" as (update "asset" set "id" = $1, "checksum" = $2, "originalPath" = $3, "type" = $4, "originalFileName" = $5, "deviceAssetId" = $6, "deviceId" = $7, "fileCreatedAt" = $8, "fileModifiedAt" = $9, "localDateTime" = $10, "duration" = $11, "livePhotoVideoId" = $12, "sidecarPath" = $13 where "id" = $14::uuid returning *) select "asset".*, to_json("asset_exif") as "exifInfo", (select coalesce(json_agg(agg), '[]') from (select "asset_face".*, "person" as "person" from "asset_face" left join lateral (select "person".* from "person" where "asset_face"."personId" = "person"."id") as "person" on true where "asset_face"."assetId" = "asset"."id" and "asset_face"."deletedAt" is null) as agg) as "faces" from "asset" left join "asset_exif" on "asset"."id" = "asset_exif"."assetId"`,
  params: [
    'bdf7f148-c0d5-45f4-858d-1be1d38f5edb',
    <Buffer many hex chars here>,
    '/usr/src/app/upload/upload/6776bd1f-4f7a-420e-ae4a-1e41cd23c5a4/77/a0/77a08d53-dbd8-4dde-8b06-584e9cc3e08f.jpeg',
    'IMAGE',
    'IMG_9864.jpeg',
    'web-IMG_9864.jpeg-1754235394000',
    'WEB',
    2025-08-03T15:36:34.000Z,
    2025-08-03T15:36:34.000Z,
    2025-08-03T15:36:34.000Z,
    '0:00:00.000000',
    null,
    null,
    'bdf7f148-c0d5-45f4-858d-1be1d38f5edb'
  ]
}
@adzwoolly commented on GitHub (Aug 3, 2025): Ah yes, I forgot to mention the reverse proxy. Accessing the server and port directly performs a different request but, still doesn't appear to update the image. `PUT http://192.168.1.125:2283/api/assets/bdf7f148-c0d5-45f4-858d-1be1d38f5edb/original` with a body that has some image data and what I presume is binary data of the image itself. immich_server now has an error in the logs: ``` Query failed : { durationMs: 7.740293994545937, error: PostgresError: duplicate key value violates unique constraint "UQ_assets_owner_checksum" at ErrorResponse (/usr/src/app/server/node_modules/postgres/cjs/src/connection.js:794:26) at handle (/usr/src/app/server/node_modules/postgres/cjs/src/connection.js:480:6) at Socket.data (/usr/src/app/server/node_modules/postgres/cjs/src/connection.js:315:9) at Socket.emit (node:events:518:28) at addChunk (node:internal/streams/readable:561:12) at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) at Readable.push (node:internal/streams/readable:392:5) at TCP.onStreamRead (node:internal/stream_base_commons:189:23) at TCP.callbackTrampoline (node:internal/async_hooks:130:17) { severity_local: 'ERROR', severity: 'ERROR', code: '23505', detail: 'Key ("ownerId", checksum)=(6776bd1f-4f7a-420e-ae4a-1e41cd23c5a4, \\x006b0fe90387e57b7656476f7eee564b5b359459) already exists.', schema_name: 'public', table_name: 'asset', constraint_name: 'UQ_assets_owner_checksum', file: 'nbtinsert.c', line: '663', routine: '_bt_check_unique' }, sql: `with "asset" as (update "asset" set "id" = $1, "checksum" = $2, "originalPath" = $3, "type" = $4, "originalFileName" = $5, "deviceAssetId" = $6, "deviceId" = $7, "fileCreatedAt" = $8, "fileModifiedAt" = $9, "localDateTime" = $10, "duration" = $11, "livePhotoVideoId" = $12, "sidecarPath" = $13 where "id" = $14::uuid returning *) select "asset".*, to_json("asset_exif") as "exifInfo", (select coalesce(json_agg(agg), '[]') from (select "asset_face".*, "person" as "person" from "asset_face" left join lateral (select "person".* from "person" where "asset_face"."personId" = "person"."id") as "person" on true where "asset_face"."assetId" = "asset"."id" and "asset_face"."deletedAt" is null) as agg) as "faces" from "asset" left join "asset_exif" on "asset"."id" = "asset_exif"."assetId"`, params: [ 'bdf7f148-c0d5-45f4-858d-1be1d38f5edb', <Buffer many hex chars here>, '/usr/src/app/upload/upload/6776bd1f-4f7a-420e-ae4a-1e41cd23c5a4/77/a0/77a08d53-dbd8-4dde-8b06-584e9cc3e08f.jpeg', 'IMAGE', 'IMG_9864.jpeg', 'web-IMG_9864.jpeg-1754235394000', 'WEB', 2025-08-03T15:36:34.000Z, 2025-08-03T15:36:34.000Z, 2025-08-03T15:36:34.000Z, '0:00:00.000000', null, null, 'bdf7f148-c0d5-45f4-858d-1be1d38f5edb' ] } ```
Author
Owner

@bo0tzz commented on GitHub (Aug 3, 2025):

That error in the log means the file you're trying to upload already exists in Immich. That's presumably also why the previous request (to bulk-upload-check) was the last thing you're seeing there, as the response would've been the server saying not to bother uploading the file.

@bo0tzz commented on GitHub (Aug 3, 2025): That error in the log means the file you're trying to upload already exists in Immich. That's presumably also why the previous request (to `bulk-upload-check`) was the last thing you're seeing there, as the response would've been the server saying not to bother uploading the file.
Author
Owner

@adzwoolly commented on GitHub (Aug 3, 2025):

My apologies, you're right. My friend had uploaded the new photos to the album and I downloaded them so I could try to replace the old ones (at the time thinking EXIF data would be maintained - Immich data is though I think). I never removed the copy they uploaded, hence the duplicate.

When navigating around the web application, some pages had a dialog showing the batch upload had been marked as a duplicate but, it's not visible all the time and not on the page you're performing the action.

I'll close this now, as it doesn't accurately describe the issue. There isn't a bug, just some confusion around the UX in what I might describe as a bit of an edge case.

Edit: thank you for the help!

@adzwoolly commented on GitHub (Aug 3, 2025): My apologies, you're right. My friend had uploaded the new photos to the album and I downloaded them so I could try to replace the old ones (at the time thinking EXIF data would be maintained - Immich data is though I think). I never removed the copy they uploaded, hence the duplicate. When navigating around the web application, some pages had a dialog showing the batch upload had been marked as a duplicate but, it's not visible all the time and not on the page you're performing the action. I'll close this now, as it doesn't accurately describe the issue. There isn't a bug, just some confusion around the UX in what I might describe as a bit of an edge case. Edit: thank you for the help!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: immich-app/immich#6722