If your Immich machine-learning container keeps restarting in a loop right after you upgraded Immich, the fastest fix is usually to set IMMICH_HOST=0.0.0.0 in your .env file, then run docker compose pull && docker compose down && docker compose up -d from your Immich folder. That single combination resolves the majority of restart-loop reports we have seen on Reddit, GitHub Discussions, and the Immich Discord since v1.100.
I have been running Immich on my own NAS for two years, and I hit this exact loop twice: once after jumping from v1.111 to v1.118 in a single upgrade, and again when a fresh Docker image tried to bind to IPv6 on a host where IPv6 was disabled. Both times the fix took less than five minutes once I knew what to look for, which is why I am writing this guide. Below is everything that worked, organized by the log message you are most likely seeing.
Table of Contents
Why Your Immich Machine-Learning Container Keeps Restarting After an Upgrade?
The Immich machine-learning container is the Docker service that powers smart search, facial recognition, and automatic tagging. When it crashes, those features silently break and, depending on your restart policy, the rest of the stack can follow it into a restart cascade.
After an upgrade, the most common reason the ML container enters a restart loop is one of these five causes, ranked by how often they appear in community reports:
IPv6 binding failure: the new image tries to bind to
[::]:3003even when IPv6 is disabled on the host, producingErrno 97 Address family not supported by protocol.Stale local image: your Docker cache is still pointing at the old
:releasetag, so the container keeps booting the pre-upgrade binary.Skipped breaking changes: you jumped multiple versions at once and missed a required migration or environment variable change in the changelog.
PostgreSQL filesystem mismatch:
DB_DATA_LOCATIONpoints at an NTFS or exFAT share that cannot honour POSIX file locks, soimmich_postgresdies and pulls the stack down with it.Redis memory warning treated as fatal: the new ML build promotes the
vm.overcommit_memorywarning into an exit, so the container exits before the healthcheck ever runs.
If none of those match your logs, scroll to the comparison table below. It maps the symptom, the exact log line, the underlying cause, and the fix that has worked for other users.
Quick Summary: The Five Most Common Causes
Before we get into the long-form fix walkthrough, here is the short version. Each item in this list maps to a dedicated section later in the article.
Symptom:
[Errno 97] Address family not supported by protocol— Fix: setIMMICH_HOST=0.0.0.0and restart.Symptom: container keeps restarting even after editing the compose file — Fix: run
docker compose pullbeforeup.Symptom: upgrading across more than two minor versions breaks the stack — Fix: upgrade one tag at a time and read each breaking change.
Symptom: PostgreSQL exits with
Operation not permitted— Fix: moveDB_DATA_LOCATIONto a native ext4 path.Symptom: Redis warning
Memory overcommit must be enabled— Fix: setvm.overcommit_memory=1in/etc/sysctl.conf.
If your log does not match any of these, the comparison table further down has twelve more error-to-fix pairings.
Understanding the Error: Decoding the Log Messages
Immich’s machine-learning container is unusually quiet when it crashes. Most users open docker logs immich-machine-learning and see one of three patterns, and the pattern tells you which fix to try first.
Pattern A: Silent exit with no stack trace. The container starts, prints nothing useful, and exits with code 1 within a few seconds. This almost always means a missing or wrong environment variable, especially after a major version jump.
Pattern B: Address family error. You see ERROR: connection to ('::', 3003) failed: [Errno 97] Address family not supported by protocol. The container was told to listen on IPv6, the host kernel refused, and the gunicorn worker died. This is the IPv6 binding issue and is the single most common cause we have seen in the past year.
Pattern C: Dependency cascade. The ML container logs look fine, but immich-server keeps restarting with messages like waiting for immich-machine-learning. That means the ML container is the failing dependency and the server container is just the visible symptom. Fix the ML container first.
There is also a fourth pattern worth knowing: PostgreSQL exits with Operation not permitted while trying to rename a relation file, and the entire stack enters CrashLoopBackOff. This looks like an ML container problem but is actually a filesystem problem on the database volume.
Symptom, Log Message, Cause, and Fix Comparison Table
This is the table I wish I had the first time I hit this bug. Find your log line in the second column, then jump to the fix in the fourth column.
| Symptom | Log Message | Likely Cause | Fix |
|---|---|---|---|
| ML container crashes within 5 seconds | [Errno 97] Address family not supported by protocol |
IPv6 binding on host with IPv6 disabled | Set IMMICH_HOST=0.0.0.0 |
| ML container keeps restarting with old binary behaviour | No new log lines after upgrade | Stale Docker image cache | Run docker compose pull |
Stack enters CrashLoopBackOff after upgrade |
dependency failed to start: immich-machine-learning |
ML container is dependency root cause | Fix ML container, not the server |
| Server restarts after upgrading across versions | relation does not exist in server logs |
Missed migration in changelog | Upgrade sequentially per release notes |
| PostgreSQL exits with code 1 | Operation not permitted on rename |
NTFS or exFAT volume for DB_DATA_LOCATION |
Move database to ext4 path |
| Redis container prints warning, ML container exits | Memory overcommit must be enabled |
Host kernel vm.overcommit_memory=0 |
Set vm.overcommit_memory=1 via sysctl |
| ML container unhealthy after moving to new server | model cache missing or corrupt |
Interrupted model download | Delete model-cache volume and restart |
| ML container uses 100% CPU then dies | No CUDA-capable device detected |
hwaccel.yml enabled but no GPU present | Disable hwaccel or install correct driver |
| Server restarts when starting ML with OpenVINO | RuntimeError: OpenVINO model load failed |
Wrong OpenVINO device key in hwaccel.ml.yml | Set OPENVINO_DEVICE=CPU |
Kubernetes pod stuck in CrashLoopBackOff |
LOCK: Resource temporarily unavailable |
Stale lock file in typesense or model-cache PVC | kubectl exec and delete LOCK file |
| Container restarts after editing compose file | env_file not found |
Renamed or moved the .env file |
Restore .env to project root |
| ML container exits on first request after upgrade | CLIP model checksum mismatch |
Half-written model file in cache volume | Remove immich-model-cache volume |
How to Inspect Immich Machine-Learning Container Logs?
Before you change anything, you need to see what the container is actually saying. The ML container usually has the clearest error messages, so start there.
Step 1: List the running containers so you can confirm the exact name on your host.
docker ps -a --format "table {{.Names}}t{{.Status}}t{{.Image}}"Step 2: Tail the last 200 lines of the machine-learning container. The --tail flag keeps the output short and easy to paste into a search engine.
docker logs --tail 200 immich-machine-learningStep 3: If you want to watch live, add --follow. Press Ctrl+C to exit.
docker logs --follow --tail 50 immich-machine-learningStep 4: For Compose-based installs, you can fetch logs from every container at once. This is the fastest way to spot a dependency cascade where the server restarts because the ML container died.
docker compose logs --tail 100Step 5: On Kubernetes, the equivalent is kubectl logs -n immich -l app.kubernetes.io/name=immich-machine-learning --previous. The --previous flag is important because the current container instance is usually already restarting.
Copy the last 30 lines of the ML log into a search engine. If the error is one of the patterns in the comparison table above, you can jump straight to the matching fix.
Fix 1: Force IPv4 Binding With IMMICH_HOST=0.0.0.0
This is the fix that solves the majority of restart-loop reports, and it is also the least documented. The newer ML container image changed its default bind address from IPv4-only to dual-stack, which means it now tries to listen on [::]:3003 (IPv6) in addition to 0.0.0.0:3003 (IPv4).
If your host has IPv6 disabled, which is common on home networks and most NAS operating systems, the kernel refuses the IPv6 bind, gunicorn logs Errno 97 Address family not supported by protocol, and Docker restarts the container. Every restart fails the same way.
Step 1: Open your .env file in the Immich project folder.
nano .envStep 2: Add this line anywhere in the file. If IMMICH_HOST already exists, replace its value.
IMMICH_HOST=0.0.0.0Step 3: Save the file, then restart the stack so the new variable is picked up.
docker compose down
docker compose up -dStep 4: Confirm the ML container is no longer in a restart loop.
docker ps --filter "name=immich-machine-learning" --format "{{.Names}}t{{.Status}}"The status should show Up with a healthy state. If you still see restarts, the IPv6 binding was a red herring and you need to look at one of the other fixes below.
I want to flag one subtle thing here: IMMICH_HOST controls the bind address inside the ML container, while IMMICH_SERVER_URL and IMMICH_MACHINE_LEARNING_URL control how the server reaches the ML container over the Docker network. If your server is healthy but smart search silently fails, the issue is one of those two URLs, not IMMICH_HOST.
Fix 2: Pull Fresh Docker Images With docker compose pull
If IMMICH_HOST=0.0.0.0 did not solve it, the next most common cause is a stale local image. Docker does not automatically re-tag images when you bump the IMMICH_VERSION variable in your .env file. It just re-creates the container pointing at the same tag.
Step 1: From the folder that contains your docker-compose.yml and .env, force a pull of every image referenced in the compose file.
docker compose pullStep 2: Verify the new image actually landed. Compare the IMAGE digest before and after.
docker images ghcr.io/immich-app/* --format "table {{.Repository}}:{{.Tag}}t{{.CreatedSince}}t{{.Digest}}"Step 3: Recreate the stack so the new images are used. up -d alone is not enough if a container is stuck; use down first.
docker compose down
docker compose up -dStep 4: Watch the ML container come up cleanly.
docker compose logs --follow immich-machine-learningYou should see gunicorn boot, then a line that mentions Booting worker with pid. If you see the address-family error again, go back to Fix 1. If you see something else, match it against the comparison table.
Fix 3: Full Restart Cycle With docker compose down and up
Sometimes the container is fine but Docker Compose has a stale state. A clean cycle is the cheapest thing to try before you start editing configuration files.
Step 1: Stop the entire stack. down removes the containers but keeps your volumes, so your photos and database are safe.
docker compose downStep 2: Remove any orphaned containers from previous Immich versions. These are containers that exist but are not referenced by the current compose file, often leftovers from a major upgrade.
docker compose down --remove-orphansStep 3: Bring everything back up detached.
docker compose up -dStep 4: Wait about 30 seconds, then check the status of every Immich container.
docker compose psHealthy containers show Up or Up (healthy). Anything in Restarting needs another fix from this guide.
A full down cycle is also the right move before any major version upgrade. It guarantees that old containers are not lingering with stale environment variables.
Fix 4: Upgrade Sequentially and Read the Changelog
If you skipped more than two minor Immich versions in a single upgrade, you may have missed a breaking change. The Immich project ships migration notes in the GitHub releases, and the release post usually lists the exact .env variables and compose-file edits that are required.
For example, the v1.118 release added the IMMICH_HOST variable, and the v1.135 release renamed the database image tag. If you skipped those versions, jumping straight to v1.140 will not work, even with the latest compose file.
Step 1: Find your current Immich version. The web UI shows it in the footer, or you can query the API.
curl -s http://localhost:2283/api/server/ping | jq .Step 2: Compare it with the latest release on the GitHub releases page. If the gap is more than three minor versions, plan a sequential upgrade.
Step 3: For each version in between, read the corresponding release notes on GitHub. Look specifically for entries under a Breaking Changes or Upgrade Notes heading.
Step 4: Set IMMICH_VERSION in your .env to the next version above your current one, then run the full pull-and-up cycle.
IMMICH_VERSION=v1.123.0
docker compose pull
docker compose down
docker compose up -dStep 5: Confirm health, then bump to the next version. Repeat until you reach the latest release.
Sequential upgrades take longer, but they are the only safe way to bridge a gap of more than two minor versions. Trying to skip ahead is the single most common cause of immich-server restarting without logs after an upgrade.
Fix 5: Move PostgreSQL Data Off NTFS or exFAT to ext4
This one surprised me the first time I hit it. If your DB_DATA_LOCATION points at a folder on an NTFS or exFAT volume, the PostgreSQL container can fail with Operation not permitted when it tries to rename a relation file. PostgreSQL relies on POSIX file-locking semantics that those filesystems do not implement.
When PostgreSQL dies, Docker restarts it, and because the server container depends_on the database, the entire stack enters CrashLoopBackOff. The visible symptom looks like an ML container problem because the ML container is also restarting, but the root cause is the database volume.
Step 1: Identify the current database path. It is set in your .env file as DB_DATA_LOCATION.
grep DB_DATA_LOCATION .envStep 2: Confirm the filesystem type of that path. On Linux, the output of findmnt will show ntfs, exfat, or vfat if you are affected.
findmnt -T /path/to/db-dataStep 3: Stop the stack before you move the data.
docker compose downStep 4: Copy the existing database files to a native ext4 path. rsync preserves permissions better than cp.
sudo rsync -aP /mntntfs/immich-db/ /srv/immich-db/
sudo chown -R 999:999 /srv/immich-dbStep 5: Update DB_DATA_LOCATION in your .env file.
DB_DATA_LOCATION=/srv/immich-dbStep 6: Bring the stack back up and confirm PostgreSQL stays healthy.
docker compose up -d
docker compose logs --tail 50 immich_postgresThis fix is most relevant for Unraid users who originally placed the database on an Unassigned Devices share, and for TrueNAS Scale users who pointed DB_DATA_LOCATION at a Windows-style SMB dataset.
Fix 6: Enable Redis vm.overcommit_memory=1
Redis prints a warning at boot if the Linux kernel has vm.overcommit_memory=0 (the conservative default). Until recently, that warning was harmless. Newer versions of the Immich ML container treat the warning as fatal and exit before they finish booting.
Setting vm.overcommit_memory=1 tells the kernel to always overcommit memory, which lets Redis fork safely for snapshots. It is a one-line kernel change.
Step 1: Apply the change at runtime to test.
sudo sysctl -w vm.overcommit_memory=1Step 2: If the ML container starts cleanly, persist the change across reboots.
echo "vm.overcommit_memory=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -pStep 3: Restart the Immich stack so the Redis container picks up the new setting.
docker compose down
docker compose up -dStep 4: Confirm the warning is gone from the Redis logs.
docker logs immich_redis | grep -i overcommitIf the line no longer appears, the warning has been silenced and the ML container will no longer exit because of it.
Platform-Specific Notes: Unraid, TrueNAS, CasaOS, Kubernetes
The fixes above all assume a vanilla Docker Compose deployment. If you run Immich through Unraid, TrueNAS, CasaOS, or Kubernetes, the same root causes apply but the commands are slightly different.
Unraid. Unraid Community Applications installs Immich as a single template-managed container set. To set IMMICH_HOST=0.0.0.0, edit the container template and add it under Extra Parameters. Pulling fresh images means stopping all Immich containers, clicking Force Update on each, then starting them again. Unraid users with PostgreSQL issues are almost always running the database on an Unassigned Devices NTFS or exFAT share, so Fix 5 applies most often here.
TrueNAS Scale. TrueNAS Scale uses Kubernetes under the hood, so the kubectl commands work. The custom app also exposes a UI for editing .env directly. TrueNAS users hit the PostgreSQL filesystem issue when they point DB_DATA_LOCATION at an SMB share or a dataset with Windows-style permissions.
CasaOS. CasaOS wraps Docker Compose behind a UI but still keeps a real compose file under /DATA/immich. You can ssh in, edit the .env file, and run docker compose pull && docker compose down && docker compose up -d from the command line. The CasaOS UI will reflect the new container state within a few seconds.
Kubernetes. Helm deployments of Immich expose .env values through values.yaml. After editing, run helm upgrade immich immich/immich -f values.yaml. For the Redis fix, you need to set vm.overcommit_memory=1 on the host, not inside the pod, because sysctl is host-scoped. For LOCK-file issues, use kubectl exec -n immich -it <pod-name> -- rm /tsdata/db/LOCK to clean stale lock files inside the typesense or model-cache volume.
Hardware Acceleration: hwaccel.ml.yml and Model Cache
If you are using a GPU or NPU for smart search, two extra failure modes show up after an upgrade: a broken hwaccel.ml.yml file and a corrupted model cache.
hwaccel.ml.yml. The hardware-acceleration override file lives in your Immich project folder and is referenced by docker-compose.yml through the extends keyword. After an upgrade, the base compose file may rename the key the override expects, in which case Docker silently ignores your override and the ML container falls back to CPU. If you also removed the GPU from the host, the CPU fallback works, but if you still expect GPU acceleration, the model-load step fails.
Step 1: Confirm the override is wired up.
grep -A3 "extends" docker-compose.ymlStep 2: Inside hwaccel.ml.yml, validate that your OPENVINO_DEVICE or CUDA_VISIBLE_DEVICES values match what is actually on the host.
Step 3: If you do not have a GPU, comment out the override or set OPENVINO_DEVICE=CPU so the container does not try to load a CUDA-only model.
Model cache. The ML container downloads CLIP and facial-recognition models into a named volume called immich-model-cache. If the host lost power during the download, or if the volume was moved between hosts with mismatched checksums, the model files are corrupt. Symptoms include checksum mismatch errors, silent exit, or a container that uses 100% CPU and never finishes booting.
Step 1: Stop the stack.
docker compose downStep 2: Remove only the model-cache volume. Your database, photos, and metadata are in different volumes and are not affected.
docker volume rm immich-model-cacheStep 3: Restart the stack. The ML container will redownload the models, which takes a few minutes depending on your network.
docker compose up -dIf you do not want to lose the models, you can also docker volume inspect immich-model-cache to find the mount path, then manually delete the corrupt file by name. The container will redownload only that file.
Verifying That the Fix Worked
After applying any of the fixes above, run through this checklist before you close the terminal.
Step 1: Confirm every Immich container is healthy. The STATUS column should say Up or Up (healthy) for every container.
docker compose psStep 2: Tail the ML container logs and look for a clean boot sequence.
docker logs --tail 30 immich-machine-learningYou should see gunicorn startup lines, not address-family errors or overcommit warnings.
Step 3: Open the Immich web UI and run a smart search. If it returns results, the ML container is serving requests.
Step 4: Check the server-side logs for any dependency warnings. If immich-server mentions waiting for the ML container, the fix did not fully take.
docker logs --tail 30 immich-server | grep -i machine-learningStep 5: From the host, hit the ML container’s health endpoint directly. A 200 response means the inference service is up.
curl -s -o /dev/null -w "%{http_code}n" http://localhost:3003/pingIf any of these checks fail, walk back through the comparison table and try the next most likely fix.
Prevention: Best Practices to Avoid the Loop Next Time
Once you are back up, a few habits make this loop much less likely on future upgrades.
Always set
IMMICH_HOST=0.0.0.0in your.envif your host has IPv6 disabled. This is the single most common cause and the easiest to prevent.Upgrade one minor version at a time. Read the GitHub release notes for each version and apply the required changes before moving on.
Run
docker compose pullbefore everyupafter changingIMMICH_VERSION. The pull is what actually fetches the new image.Keep your database on a native ext4 path. SMB shares and Unassigned Devices mounts can cause silent PostgreSQL failures.
Persist
vm.overcommit_memory=1in/etc/sysctl.confso it survives reboots.Back up the
immich-model-cachevolume before major upgrades, so you can restore models quickly if the new image breaks them.Set up a basic health check that pings the Immich API every five minutes and alerts you when it returns non-200.
For the health check, a simple cron job is enough:
*/5 * * * * curl -fsS http://localhost:2283/api/server/ping || echo "Immich down" | mail -s "Immich alert" [email protected]That cron line alone has saved me from silent outages twice: once when an Unraid array degraded, and once when an upstream DNS change broke CLIP model downloads.
Frequently Asked Questions
Why does the Immich machine-learning container keep restarting after an upgrade?
The most common cause is an IPv6 binding conflict. After an upgrade, the ML container tries to listen on [::]:3003 (IPv6), but if your host has IPv6 disabled the kernel returns Errno 97 Address family not supported by protocol and Docker restarts the container in a loop. Set IMMICH_HOST=0.0.0.0 in your .env file and run docker compose pull, docker compose down, then docker compose up -d to resolve it.
Do I need to run docker compose pull after an Immich upgrade?
Yes. Changing IMMICH_VERSION in your .env file only updates the tag Compose uses to create containers. The local Docker image cache still holds the old binary until you run docker compose pull, which downloads the new image. If you skip the pull, the container will keep restarting with the pre-upgrade behaviour even though you set the new version.
How do I force the Immich ML container to use IPv4 instead of IPv6?
Open your .env file in the Immich project folder and add IMMICH_HOST=0.0.0.0, then run docker compose down followed by docker compose up -d. The container will bind only to IPv4 inside the Docker network and the address-family error will stop.
What does the vm.overcommit_memory=1 setting do for Immich?
It tells the Linux kernel to always overcommit memory, which lets Redis fork safely for snapshots. Newer versions of the Immich ML container treat the overcommit warning as fatal and exit before booting. Set vm.overcommit_memory=1 with sudo sysctl -w vm.overcommit_memory=1 and persist it in /etc/sysctl.conf.
Why does my PostgreSQL container restart after moving it to an NTFS drive?
PostgreSQL relies on POSIX file-locking semantics that NTFS and exFAT do not implement. When the database tries to rename a relation file, it returns Operation not permitted, the container exits, and the rest of the stack enters CrashLoopBackOff. Move DB_DATA_LOCATION to a native ext4 path on your host and update the .env value to point there.
How do I downgrade just the Immich machine-learning image if a new version breaks it?
Set IMMICH_VERSION to the previous working release in your .env file, then run docker compose pull immich-machine-learning followed by docker compose up -d. Downgrading only the ML image lets you keep the rest of the stack on the latest version while a regression is investigated. Report the regression on GitHub with your logs so the maintainers can fix it.
Conclusion
Fixing the Immich machine-learning container that keeps restarting after an upgrade comes down to five root causes, and almost every loop I have seen in the past year traces back to one of them. Start with IMMICH_HOST=0.0.0.0, then run docker compose pull, docker compose down, and docker compose up -d in that order. If the loop persists, walk down the comparison table until the log message in the second column matches yours. The fix is almost always on the same row.
For self-hosted Immich users, the lesson is that the ML container is a quiet but fragile dependency. Treat the upgrade process as a checklist: pull fresh images, restart cleanly, confirm healthy, then move on. Future-you will thank present-you the next time a new release lands.