<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.wilsoz.com/index.php?action=history&amp;feed=atom&amp;title=Postmortems%2F2026-04-15_Immich_Crash</id>
	<title>Postmortems/2026-04-15 Immich Crash - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.wilsoz.com/index.php?action=history&amp;feed=atom&amp;title=Postmortems%2F2026-04-15_Immich_Crash"/>
	<link rel="alternate" type="text/html" href="https://wiki.wilsoz.com/index.php?title=Postmortems/2026-04-15_Immich_Crash&amp;action=history"/>
	<updated>2026-07-06T07:34:57Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://wiki.wilsoz.com/index.php?title=Postmortems/2026-04-15_Immich_Crash&amp;diff=19&amp;oldid=prev</id>
		<title>Wikibot: Migrated from postmortems/2026-04-15-immich-crash.md</title>
		<link rel="alternate" type="text/html" href="https://wiki.wilsoz.com/index.php?title=Postmortems/2026-04-15_Immich_Crash&amp;diff=19&amp;oldid=prev"/>
		<updated>2026-07-05T18:17:36Z</updated>

		<summary type="html">&lt;p&gt;Migrated from postmortems/2026-04-15-immich-crash.md&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;#039;&amp;#039;As of: 2026-07-05 — migrated from `postmortems/2026-04-15-immich-crash.md`&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
= Postmortem: Immich Crash &amp;amp; Service Degradation =&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Date:&amp;#039;&amp;#039;&amp;#039; 2026-04-15  &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Duration:&amp;#039;&amp;#039;&amp;#039; Unknown start → resolved ~22:30 CST  &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Severity:&amp;#039;&amp;#039;&amp;#039; High — Immich completely unavailable, photos inaccessible  &lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Status:&amp;#039;&amp;#039;&amp;#039; Resolved&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
Immich became unavailable due to a Docker bridge networking bug that left the server container unable to reach Redis. When the server was restarted to fix this, a second problem emerged: 11,744 assets in the database had missing source files on disk, causing the thumbnail generation job queue to storm-crash the process with exit code 139 (SIGSEGV) on every boot. The server then entered a persistent crash-restart loop. Root causes were identified, the bad assets were cleaned up in the database, and the server was restored to full health.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Timeline ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Time (CST)&lt;br /&gt;
! Event&lt;br /&gt;
|-&lt;br /&gt;
| Unknown&lt;br /&gt;
| Docker bridge veth bug silently breaks immich_server → immich_redis routing&lt;br /&gt;
|-&lt;br /&gt;
| Unknown&lt;br /&gt;
| Server begins crash-restart loop (Redis unreachable, EHOSTUNREACH)&lt;br /&gt;
|-&lt;br /&gt;
| ~21:00&lt;br /&gt;
| User reports Immich down; authenticated successfully but immediately logged out&lt;br /&gt;
|-&lt;br /&gt;
| ~21:05&lt;br /&gt;
| Investigation: &amp;lt;code&amp;gt;docker ps&amp;lt;/code&amp;gt; shows immich_server &amp;quot;Up 46 seconds&amp;quot; — crash-looping&lt;br /&gt;
|-&lt;br /&gt;
| ~21:10&lt;br /&gt;
| Root cause 1 identified: &amp;lt;code&amp;gt;EHOSTUNREACH 172.18.0.3:6379&amp;lt;/code&amp;gt; — server can&amp;#039;t reach Redis despite same bridge network&lt;br /&gt;
|-&lt;br /&gt;
| ~21:10&lt;br /&gt;
| Root cause 2 identified: &amp;lt;code&amp;gt;immich_postgres&amp;lt;/code&amp;gt; health check failing — stale checksum failure counter from April 4&lt;br /&gt;
|-&lt;br /&gt;
| ~21:10&lt;br /&gt;
| Fix 1: &amp;lt;code&amp;gt;pg_stat_reset()&amp;lt;/code&amp;gt; clears stale checksum counter → postgres becomes healthy&lt;br /&gt;
|-&lt;br /&gt;
| ~21:15&lt;br /&gt;
| Fix 2: &amp;lt;code&amp;gt;docker compose down &amp;amp;&amp;amp; docker compose up -d&amp;lt;/code&amp;gt; on immich stack — recreates bridge network, resolves veth bug&lt;br /&gt;
|-&lt;br /&gt;
| ~21:20&lt;br /&gt;
| Server comes up healthy. User attempts thumbnail regeneration from admin UI&lt;br /&gt;
|-&lt;br /&gt;
| ~21:22&lt;br /&gt;
| Server crashes immediately with exit code 139 (SIGSEGV)&lt;br /&gt;
|-&lt;br /&gt;
| ~21:25&lt;br /&gt;
| Root cause 3 identified: thumbnail job queue flooded with 11,744+ jobs for missing files; sharp native library segfaults under parallel failure storm&lt;br /&gt;
|-&lt;br /&gt;
| ~21:30&lt;br /&gt;
| Redis thumbnail queue cleared; server stabilises&lt;br /&gt;
|-&lt;br /&gt;
| ~21:35&lt;br /&gt;
| Analysis: 34,397 library assets in DB; only 22,634 files on disk — 11,744 missing&lt;br /&gt;
|-&lt;br /&gt;
| ~21:40&lt;br /&gt;
| sharp tested against all 22,634 on-disk image files — only 4 failures (XMP sidecar files, not real images)&lt;br /&gt;
|-&lt;br /&gt;
| ~21:45&lt;br /&gt;
| Fix 3: 11,744 missing assets marked &amp;lt;code&amp;gt;status=trashed&amp;lt;/code&amp;gt; in DB; 4 XMP entries deleted&lt;br /&gt;
|-&lt;br /&gt;
| ~22:00&lt;br /&gt;
| Server confirmed stable, all assets healthy, thumbnail generation safe to re-run&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Root Causes ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Docker Bridge veth Bug ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;What happened:&amp;#039;&amp;#039;&amp;#039; After a prior crash-restart cycle, the immich_server container&amp;#039;s virtual Ethernet interface lost routing to other containers on the same Docker bridge network. From the server&amp;#039;s perspective, Redis at &amp;lt;code&amp;gt;172.18.0.3&amp;lt;/code&amp;gt; was unreachable (&amp;lt;code&amp;gt;EHOSTUNREACH&amp;lt;/code&amp;gt;), despite Redis being healthy and all containers nominally on the same &amp;lt;code&amp;gt;immich_default&amp;lt;/code&amp;gt; bridge.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Why it happened:&amp;#039;&amp;#039;&amp;#039; This is a known Docker bug where the kernel&amp;#039;s bridge forwarding state for a container&amp;#039;s veth pair becomes stale after a crash-restart cycle. &amp;lt;code&amp;gt;docker ps&amp;lt;/code&amp;gt; shows the container as &amp;quot;Up&amp;quot; but inter-container routing is broken. The bug does not self-heal.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Detection:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;docker logs immich_server&amp;lt;/code&amp;gt; showed continuous &amp;lt;code&amp;gt;EHOSTUNREACH 172.18.0.3:6379&amp;lt;/code&amp;gt;. Host could ping 172.18.0.3 fine; the server container could not.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Fix:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;docker compose down &amp;amp;&amp;amp; docker compose up -d&amp;lt;/code&amp;gt; — tearing down and recreating the network is the only fix. &amp;lt;code&amp;gt;docker compose restart&amp;lt;/code&amp;gt; does &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; work as it doesn&amp;#039;t recreate the bridge.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 2. Stale Postgres Checksum Failure Counter ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;What happened:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;immich_postgres&amp;lt;/code&amp;gt; was marked &amp;lt;code&amp;gt;(unhealthy)&amp;lt;/code&amp;gt; by Docker, which prevented &amp;lt;code&amp;gt;immich_server&amp;lt;/code&amp;gt; from starting (it has &amp;lt;code&amp;gt;depends_on: database: condition: service_healthy&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Why it happened:&amp;#039;&amp;#039;&amp;#039; A single page checksum failure occurred on April 4 (11 days prior). The failure count accumulates in &amp;lt;code&amp;gt;pg_stat_database&amp;lt;/code&amp;gt; and is never reset automatically. The health check queries &amp;lt;code&amp;gt;SUM(checksum_failures)&amp;lt;/code&amp;gt; and exits non-zero if &amp;gt; 0, so the container stayed unhealthy indefinitely even though the database was functioning normally and no data corruption was present.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Detection:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;docker inspect immich_postgres --format &amp;#039;{{json .State.Health}}&amp;#039;&amp;lt;/code&amp;gt; showed &amp;lt;code&amp;gt;checksum failure count is 1&amp;lt;/code&amp;gt; with last failure &amp;lt;code&amp;gt;2026-04-04&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Fix:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;docker exec immich_postgres psql -U postgres -d immich -c &amp;quot;SELECT pg_stat_reset();&amp;quot;&amp;lt;/code&amp;gt; resets all per-database statistics including the checksum counter. The health check immediately passed on the next interval.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Note:&amp;#039;&amp;#039;&amp;#039; A real checksum failure is worth investigating — it can indicate a dying disk. In this case the single failure was old and isolated; the database was consistent and Immich was functioning (HTTP 200) right up until the networking broke. Monitor for recurrence.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 3. Missing Asset Crash Loop (Primary Crash Cause) ===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;What happened:&amp;#039;&amp;#039;&amp;#039; When thumbnail generation was triggered, the BullMQ job queue was flooded with ~11,744 jobs for assets whose source files no longer exist on disk. The Node.js worker processes fired these jobs in high concurrency. The &amp;lt;code&amp;gt;sharp&amp;lt;/code&amp;gt; native image library (C++ via N-API) segfaulted under the load of simultaneous &amp;quot;Input file is missing&amp;quot; failure paths, killing the entire Node.js process with exit code 139 (SIGSEGV). Docker&amp;#039;s &amp;lt;code&amp;gt;restart: always&amp;lt;/code&amp;gt; policy restarted the server, which immediately picked up the queued jobs and crashed again — a persistent crash loop.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Why the files were missing:&amp;#039;&amp;#039;&amp;#039; 34,397 assets were stored in the &amp;quot;uploaded library&amp;quot; path (&amp;lt;code&amp;gt;/usr/src/app/upload/library/&amp;lt;/code&amp;gt;). Only 22,634 files exist on disk. The gap of 11,744 likely accumulated over time as photos were moved, deleted from the host filesystem, or sourced from a device (e.g., iPhone backup migration) that was later reorganised without removing the Immich DB records.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Detection:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
docker logs immich_server → exit code 139 (SIGSEGV)&lt;br /&gt;
find /raid1/.../library -type f | wc -l → 22,634&lt;br /&gt;
SELECT COUNT(*) FROM asset WHERE originalPath LIKE &amp;#039;/usr/src/app/upload/library/%&amp;#039; → 34,397&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Fix (immediate):&amp;#039;&amp;#039;&amp;#039; Clear the Redis thumbnail queue to stop the crash loop:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker exec immich_redis redis-cli KEYS &amp;quot;immich_bull:thumbnailGeneration:*&amp;quot; | \&lt;br /&gt;
  xargs docker exec immich_redis redis-cli DEL&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Fix (permanent):&amp;#039;&amp;#039;&amp;#039; Mark missing assets as trashed so Immich never queues thumbnail generation for them again:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Pipe missing asset IDs into postgres to bulk-trash&lt;br /&gt;
cat /tmp/immich-missing-ids.txt | docker exec -i immich_postgres psql -U postgres -d immich -c &amp;quot;&lt;br /&gt;
CREATE TEMP TABLE missing_ids (id uuid);&lt;br /&gt;
COPY missing_ids FROM STDIN;&lt;br /&gt;
UPDATE asset SET \&amp;quot;deletedAt\&amp;quot; = NOW(), status = &amp;#039;trashed&amp;#039;&lt;br /&gt;
  WHERE id IN (SELECT id FROM missing_ids);&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Additionally, 4 XMP sidecar files (&amp;lt;code&amp;gt;.jpg.xmp&amp;lt;/code&amp;gt;) had been incorrectly indexed as image assets and deleted from the DB:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker exec immich_postgres psql -U postgres -d immich -c \&lt;br /&gt;
  &amp;quot;DELETE FROM asset WHERE \&amp;quot;originalPath\&amp;quot; LIKE &amp;#039;%.xmp&amp;#039;;&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== What Was NOT Broken ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;HEIC files from Mac auto-upload&amp;#039;&amp;#039;&amp;#039; — All passed sharp&amp;#039;s &amp;lt;code&amp;gt;metadata()&amp;lt;/code&amp;gt; test. Pillow (used for the corruption scan) doesn&amp;#039;t support HEIC natively; those &amp;quot;failures&amp;quot; were false positives.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;External library photos&amp;#039;&amp;#039;&amp;#039; (70,840 assets in &amp;lt;code&amp;gt;/app/local-images/&amp;lt;/code&amp;gt;) — Library scan confirmed 0 offlined, all intact.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Thumbnails on disk&amp;#039;&amp;#039;&amp;#039; — 190,882 thumbnail files were present and correctly structured. No regeneration was needed for most assets.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Impact ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Area&lt;br /&gt;
! Impact&lt;br /&gt;
|-&lt;br /&gt;
| Photo browsing&lt;br /&gt;
| Complete outage — all images showed &amp;quot;Error loading image&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| New uploads&lt;br /&gt;
| Unavailable during crash loop&lt;br /&gt;
|-&lt;br /&gt;
| External library&lt;br /&gt;
| Intact, no data loss&lt;br /&gt;
|-&lt;br /&gt;
| Uploaded library&lt;br /&gt;
| 11,744 assets with no source files trashed (files were already gone before today)&lt;br /&gt;
|-&lt;br /&gt;
| Other services&lt;br /&gt;
| None — isolated to Immich stack&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Diagnostic Commands Reference ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Check all Immich container statuses&lt;br /&gt;
docker ps --filter &amp;quot;name=immich&amp;quot; --format &amp;quot;table {{.Names}}\t{{.Status}}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Check crash exit code&lt;br /&gt;
docker inspect immich_server --format &amp;#039;{{.State.ExitCode}}&amp;#039;&lt;br /&gt;
# 139 = SIGSEGV (native crash), 1 = normal error, 0 = clean exit&lt;br /&gt;
&lt;br /&gt;
# Check postgres health detail&lt;br /&gt;
docker inspect immich_postgres --format &amp;#039;{{json .State.Health}}&amp;#039; | python3 -m json.tool | tail -20&lt;br /&gt;
&lt;br /&gt;
# Clear thumbnail queue (safe to run anytime — jobs will re-queue from admin UI on demand)&lt;br /&gt;
docker exec immich_redis redis-cli KEYS &amp;quot;immich_bull:thumbnailGeneration:*&amp;quot; | \&lt;br /&gt;
  xargs docker exec immich_redis redis-cli DEL&lt;br /&gt;
&lt;br /&gt;
# Count assets by storage location&lt;br /&gt;
docker exec immich_postgres psql -U postgres -d immich -t -c &amp;quot;&lt;br /&gt;
SELECT&lt;br /&gt;
  SUM(CASE WHEN \&amp;quot;originalPath\&amp;quot; LIKE &amp;#039;/usr/src/app/upload/library/%&amp;#039; THEN 1 ELSE 0 END) as uploaded,&lt;br /&gt;
  SUM(CASE WHEN \&amp;quot;originalPath\&amp;quot; LIKE &amp;#039;/app/local-images/%&amp;#039; THEN 1 ELSE 0 END) as external,&lt;br /&gt;
  COUNT(*) FILTER (WHERE status = &amp;#039;trashed&amp;#039;) as trashed&lt;br /&gt;
FROM asset;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Find assets with missing files (run on host, translate paths)&lt;br /&gt;
# See: /home/mnw/Developer/SystemResiliency/scripts/immich-find-broken.py&lt;br /&gt;
&lt;br /&gt;
# Reset stale postgres checksum counter&lt;br /&gt;
docker exec immich_postgres psql -U postgres -d immich -c &amp;quot;SELECT pg_stat_reset();&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Follow-up Actions ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Action&lt;br /&gt;
! Priority&lt;br /&gt;
! Status&lt;br /&gt;
|-&lt;br /&gt;
| Run thumbnail generation from Immich admin → Jobs&lt;br /&gt;
| High&lt;br /&gt;
| Pending&lt;br /&gt;
|-&lt;br /&gt;
| Empty Immich trash (11,744 trashed assets)&lt;br /&gt;
| Medium&lt;br /&gt;
| Pending&lt;br /&gt;
|-&lt;br /&gt;
| Investigate why 11,744 uploaded assets lost their source files&lt;br /&gt;
| Low&lt;br /&gt;
| Pending&lt;br /&gt;
|-&lt;br /&gt;
| Monitor postgres checksum failures — recurrence may indicate disk issue&lt;br /&gt;
| Medium&lt;br /&gt;
| Ongoing&lt;br /&gt;
|-&lt;br /&gt;
| Monthly rolling restarts workflow (n8n &amp;lt;code&amp;gt;OlzWTPDsCoO9oEo7&amp;lt;/code&amp;gt;) now active&lt;br /&gt;
| Done&lt;br /&gt;
| Complete&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Prevention ==&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;monthly rolling restart workflow&amp;#039;&amp;#039;&amp;#039; deployed today (n8n ID: &amp;lt;code&amp;gt;OlzWTPDsCoO9oEo7&amp;lt;/code&amp;gt;) performs a full &amp;lt;code&amp;gt;compose down &amp;amp;&amp;amp; up -d&amp;lt;/code&amp;gt; on all service stacks on the 1st of each month at 2 AM CST. This proactively recreates Docker bridge networks before the veth bug can silently accumulate, and sends per-service status via Matrix (Zordon). The postgres checksum issue and missing asset problem are not recurring risks given the fixes applied.&lt;/div&gt;</summary>
		<author><name>Wikibot</name></author>
	</entry>
</feed>