Skip to content

People faces on ext library not detected despite running "missing" #23131

Description

@rsurgiewicz

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

  • Yes

The bug

Hi Folks,

I've been running Immich for some time (v2.0.1) updated today to v2.1.0 but issue still persists.

I have external library that is being populated overnight and I've turned on periodical scans on external library - Immich fetch new photos and videos and display correctly ✅

However newly added photos (from ext library) do not have people faces detected nor recognized.
When I run task manually

Image

Photos are being processed but still no faces is "attached" to new photos.

The only way to "attach" faces is to run reset and re-run face detection & recognition for whole set. That takes ages since my library is quite a large set.

I consider it a bug.

The OS that Immich Server is running on

TrueNas

Version of Immich Server

v.2.1.0

Version of Immich Mobile App

v2.1.0

Platform with the issue

  • Server
  • Web
  • Mobile

Device make and model

No response

Your docker-compose.yml content

configs:
  permissions_actions_data:
    content: >-
      [{"read_only": false, "mount_path":
      "/mnt/permission/pgvecto_postgres_data", "is_temporary": false,
      "identifier": "pgvecto_postgres_data", "recursive": false, "mode":
      "check", "uid": 999, "gid": 999, "chmod": null}, {"read_only": false,
      "mount_path": "/mnt/permission/redis_redis_data", "is_temporary": true,
      "identifier": "redis_redis_data", "recursive": true, "mode": "check",
      "uid": 568, "gid": 568, "chmod": null}, {"read_only": false, "mount_path":
      "/mnt/permission/ml-cache", "is_temporary": true, "identifier":
      "ml-cache", "recursive": true, "mode": "check", "uid": 568, "gid": 568,
      "chmod": null}]
  permissions_run_script:
    content: |
      #!/usr/bin/env python3

      import os
      import json
      import time
      import shutil

      with open("/script/actions.json", "r") as f:
          actions_data = json.load(f)

      if not actions_data:
          # If this script is called, there should be actions data
          raise ValueError("No actions data found")

      def fix_perms(path, chmod, recursive=False):
          print(f"Changing permissions{' recursively ' if recursive else ' '}to {chmod} on: [{path}]")
          os.chmod(path, int(chmod, 8))
          if recursive:
              for root, dirs, files in os.walk(path):
                  for f in files:
                      os.chmod(os.path.join(root, f), int(chmod, 8))
          print("Permissions after changes:")
          print_chmod_stat()

      def fix_owner(path, uid, gid, recursive=False):
          print(f"Changing ownership{' recursively ' if recursive else ' '}to {uid}:{gid} on: [{path}]")
          os.chown(path, uid, gid)
          if recursive:
              for root, dirs, files in os.walk(path):
                  for f in files:
                      os.chown(os.path.join(root, f), uid, gid)
          print("Ownership after changes:")
          print_chown_stat()

      def print_chown_stat():
          curr_stat = os.stat(action["mount_path"])
          print(f"Ownership: [{curr_stat.st_uid}:{curr_stat.st_gid}]")

      def print_chmod_stat():
          curr_stat = os.stat(action["mount_path"])
          print(f"Permissions: [{oct(curr_stat.st_mode)[3:]}]")

      def print_chown_diff(curr_stat, uid, gid):
          print(f"Ownership: wanted [{uid}:{gid}], got [{curr_stat.st_uid}:{curr_stat.st_gid}].")

      def print_chmod_diff(curr_stat, mode):
          print(f"Permissions: wanted [{mode}], got [{oct(curr_stat.st_mode)[3:]}].")

      def perform_action(action):
          if action["read_only"]:
              print(f"Path for action [{action['identifier']}] is read-only, skipping...")
              return

          start_time = time.time()
          print(f"=== Applying configuration on volume with identifier [{action['identifier']}] ===")

          if not os.path.isdir(action["mount_path"]):
              print(f"Path [{action['mount_path']}] is not a directory, skipping...")
              return

          if action["is_temporary"]:
              print(f"Path [{action['mount_path']}] is a temporary directory, ensuring it is empty...")
              for item in os.listdir(action["mount_path"]):
                  item_path = os.path.join(action["mount_path"], item)

                  # Exclude the safe directory, where we can use to mount files temporarily
                  if os.path.basename(item_path) == "ix-safe":
                      continue
                  if os.path.isdir(item_path):
                      shutil.rmtree(item_path)
                  else:
                      os.remove(item_path)

          if not action["is_temporary"] and os.listdir(action["mount_path"]):
              print(f"Path [{action['mount_path']}] is not empty, skipping...")
              return

          print(f"Current Ownership and Permissions on [{action['mount_path']}]:")
          curr_stat = os.stat(action["mount_path"])
          print_chown_diff(curr_stat, action["uid"], action["gid"])
          print_chmod_diff(curr_stat, action["chmod"])
          print("---")

          if action["mode"] == "always":
              fix_owner(action["mount_path"], action["uid"], action["gid"], action["recursive"])
              if not action["chmod"]:
                  print("Skipping permissions check, chmod is falsy")
              else:
                  fix_perms(action["mount_path"], action["chmod"], action["recursive"])
              return

          elif action["mode"] == "check":
              if curr_stat.st_uid != action["uid"] or curr_stat.st_gid != action["gid"]:
                  print("Ownership is incorrect. Fixing...")
                  fix_owner(action["mount_path"], action["uid"], action["gid"], action["recursive"])
              else:
                  print("Ownership is correct. Skipping...")

              if not action["chmod"]:
                  print("Skipping permissions check, chmod is falsy")
              else:
                  if oct(curr_stat.st_mode)[3:] != action["chmod"]:
                      print("Permissions are incorrect. Fixing...")
                      fix_perms(action["mount_path"], action["chmod"], action["recursive"])
                  else:
                      print("Permissions are correct. Skipping...")

          print(f"Time taken: {(time.time() - start_time) * 1000:.2f}ms")
          print(f"=== Finished applying configuration on volume with identifier [{action['identifier']}] ==")
          print()

      if __name__ == "__main__":
          start_time = time.time()
          for action in actions_data:
              perform_action(action)
          print(f"Total time taken: {(time.time() - start_time) * 1000:.2f}ms")
services:
  machine-learning:
    cap_drop:
      - ALL
    depends_on:
      permissions:
        condition: service_completed_successfully
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4096M
    environment:
      GID: '568'
      GROUP_ID: '568'
      HF_HOME: /mlcache
      IMMICH_LOG_LEVEL: log
      IMMICH_PORT: '32002'
      MACHINE_LEARNING_CACHE_FOLDER: /mlcache
      MPLCONFIGDIR: /mlcache/matplotlib
      NODE_ENV: production
      NVIDIA_VISIBLE_DEVICES: void
      PGID: '568'
      PUID: '568'
      TRANSFORMERS_CACHE: /mlcache
      TZ: Europe/Warsaw
      UID: '568'
      UMASK: '002'
      UMASK_SET: '002'
      USER_ID: '568'
    group_add:
      - 568
    healthcheck:
      interval: 30s
      retries: 5
      start_interval: 2s
      start_period: 15s
      test: python3 healthcheck.py
      timeout: 5s
    image: ghcr.io/immich-app/immich-machine-learning:v2.1.0-rocm
    platform: linux/amd64
    privileged: False
    restart: unless-stopped
    security_opt:
      - no-new-privileges=true
    stdin_open: False
    tty: False
    user: '568:568'
    volumes:
      - read_only: False
        source: ml-cache
        target: /mlcache
        type: volume
        volume:
          nocopy: False
  permissions:
    cap_add:
      - CHOWN
      - DAC_OVERRIDE
      - FOWNER
    cap_drop:
      - ALL
    configs:
      - mode: 320
        source: permissions_actions_data
        target: /script/actions.json
      - mode: 448
        source: permissions_run_script
        target: /script/run.py
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1024M
    entrypoint:
      - python3
      - /script/run.py
    environment:
      GID: '568'
      GROUP_ID: '568'
      NVIDIA_VISIBLE_DEVICES: void
      PGID: '568'
      PUID: '568'
      TZ: Europe/Warsaw
      UID: '568'
      UMASK: '002'
      UMASK_SET: '002'
      USER_ID: '568'
    group_add:
      - 568
    healthcheck:
      disable: True
    image: python:3.13.0-slim-bookworm
    network_mode: none
    platform: linux/amd64
    privileged: False
    restart: on-failure:1
    security_opt:
      - no-new-privileges=true
    stdin_open: False
    tty: False
    user: '0:0'
    volumes:
      - read_only: False
        source: ml-cache
        target: /mnt/permission/ml-cache
        type: volume
        volume:
          nocopy: False
      - bind:
          create_host_path: False
          propagation: rprivate
        read_only: False
        source: /mnt/naspool/apps/immich/db
        target: /mnt/permission/pgvecto_postgres_data
        type: bind
      - read_only: False
        source: redis-data
        target: /mnt/permission/redis_redis_data
        type: volume
        volume:
          nocopy: False
  pgvecto:
    cap_drop:
      - ALL
    depends_on:
      permissions:
        condition: service_completed_successfully
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4096M
    environment:
      DB_STORAGE_TYPE: HDD
      GID: '568'
      GROUP_ID: '568'
      NVIDIA_VISIBLE_DEVICES: void
      PGID: '568'
      PGPORT: '5432'
      POSTGRES_DB: immich
      POSTGRES_PASSWORD: xxxxx!
      POSTGRES_USER: immich
      PUID: '568'
      TZ: Europe/Warsaw
      UID: '568'
      UMASK: '002'
      UMASK_SET: '002'
      USER_ID: '568'
    group_add:
      - 568
    healthcheck:
      interval: 30s
      retries: 5
      start_interval: 2s
      start_period: 15s
      test:
        - CMD
        - pg_isready
        - '-h'
        - 127.0.0.1
        - '-p'
        - '5432'
        - '-U'
        - immich
        - '-d'
        - immich
      timeout: 5s
    image: ghcr.io/immich-app/postgres:15-vectorchord0.4.3-pgvectors0.2.0
    platform: linux/amd64
    privileged: False
    restart: unless-stopped
    security_opt:
      - no-new-privileges=true
    shm_size: 256M
    stdin_open: False
    tty: False
    user: '999:999'
    volumes:
      - bind:
          create_host_path: False
          propagation: rprivate
        read_only: False
        source: /mnt/naspool/apps/immich/db
        target: /var/lib/postgresql/data
        type: bind
  redis:
    cap_drop:
      - ALL
    command:
      - '--port'
      - '6379'
      - '--requirepass'
      - xxxxx!
    depends_on:
      permissions:
        condition: service_completed_successfully
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4096M
    environment:
      GID: '568'
      GROUP_ID: '568'
      NVIDIA_VISIBLE_DEVICES: void
      PGID: '568'
      PUID: '568'
      REDIS_PASSWORD: xxxxx!
      TZ: Europe/Warsaw
      UID: '568'
      UMASK: '002'
      UMASK_SET: '002'
      USER_ID: '568'
    group_add:
      - 568
    healthcheck:
      interval: 30s
      retries: 5
      start_interval: 2s
      start_period: 15s
      test:
        - CMD
        - redis-cli
        - '-h'
        - 127.0.0.1
        - '-p'
        - '6379'
        - '-a'
        - xxxxxx!
        - ping
      timeout: 5s
    image: valkey/valkey:8.1.4
    platform: linux/amd64
    privileged: False
    restart: unless-stopped
    security_opt:
      - no-new-privileges=true
    stdin_open: False
    tty: False
    user: '568:568'
    volumes:
      - read_only: False
        source: redis-data
        target: /data
        type: volume
        volume:
          nocopy: False
  server:
    cap_drop:
      - ALL
    depends_on:
      permissions:
        condition: service_completed_successfully
      pgvecto:
        condition: service_healthy
      redis:
        condition: service_healthy
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4096M
    environment:
      DB_DATABASE_NAME: immich
      DB_HOSTNAME: pgvecto
      DB_PASSWORD: xxxxxx!
      DB_PORT: '5432'
      DB_USERNAME: immich
      GID: '568'
      GROUP_ID: '568'
      IMMICH_LOG_LEVEL: log
      IMMICH_MACHINE_LEARNING_ENABLED: 'true'
      IMMICH_MACHINE_LEARNING_URL: http://machine-learning:32002
      IMMICH_PORT: '30041'
      NODE_ENV: production
      NVIDIA_VISIBLE_DEVICES: void
      PGID: '568'
      PUID: '568'
      REDIS_DBINDEX: '0'
      REDIS_HOSTNAME: redis
      REDIS_PASSWORD: xxxxxx!
      REDIS_PORT: '6379'
      TZ: Europe/Warsaw
      UID: '568'
      UMASK: '002'
      UMASK_SET: '002'
      USER_ID: '568'
    group_add:
      - 568
    healthcheck:
      interval: 30s
      retries: 5
      start_interval: 2s
      start_period: 15s
      test: immich-healthcheck
      timeout: 5s
    image: ghcr.io/immich-app/immich-server:v2.1.0
    platform: linux/amd64
    ports:
      - mode: ingress
        protocol: tcp
        published: 30041
        target: 30041
    privileged: False
    restart: unless-stopped
    security_opt:
      - no-new-privileges=true
    stdin_open: False
    tty: False
    user: '568:568'
    volumes:
      - bind:
          create_host_path: False
          propagation: rprivate
        read_only: False
        source: /mnt/naspool/apps/immich/upload
        target: /data
        type: bind
      - bind:
          create_host_path: False
          propagation: rprivate
        read_only: True
        source: /mnt/naspool/backup/DropBox/rafals_dropbox/Przesłane z aparatu
        target: /extdata/rafals_dropbox
        type: bind
volumes:
  ml-cache: {}
  redis-data: {}
x-notes: >
  # Immich


  ## Security


  **Read the following security precautions to ensure that you wish to continue
  using this application.**


  ---


  ### Container: [machine-learning]


  #### Running user/group(s)


  - User: 568

  - Group: 568

  - Supplementary Groups: apps


  ---


  ### Container: [pgvecto]


  #### Running user/group(s)


  - User: 999

  - Group: 999

  - Supplementary Groups: apps


  ---


  ### Container: [redis]


  #### Running user/group(s)


  - User: 568

  - Group: 568

  - Supplementary Groups: apps


  ---


  ### Container: [server]


  #### Running user/group(s)


  - User: 568

  - Group: 568

  - Supplementary Groups: apps


  ---


  ### Container: [permissions]


  **This container is short-lived.**


  #### Running user/group(s)


  - User: root

  - Group: root

  - Supplementary Groups: apps


  ---


  ## Bug Reports and Feature Requests


  If you find a bug in this app or have an idea for a new feature, please file
  an issue at

  https://github.com/truenas/apps
x-portals:
  - host: 0.0.0.0
    name: Web UI
    path: /
    port: 30041
    scheme: http

Your .env content

1=1

Reproduction steps

...

Relevant log output

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions