Releases: epheterson/immich-apple-silicon
Releases · epheterson/immich-apple-silicon
Release list
Immich Accelerator v1.4.7
Fixes
- Homebrew formula failed to install on every release since v1.4.4 (#31). The CI workflow that generates the formula used a bash heredoc containing backticks and em-dashes. Backticks triggered command substitution on the runner, em-dashes got mangled through the locale. Brew's Ruby installer rejected the resulting invalid UTF-8. Replaced with plain ASCII.
Upgrade
brew upgrade immich-accelerator
immich-accelerator setup # if first time or new features require itImmich Accelerator v1.4.6
Fixes
- ML service silently failed to start after brew upgrade (#29). Config stored a versioned Cellar path for
ml_dirwhich gets deleted on upgrade.cmd_startandcmd_watchnow auto-resolveml_dirvia the stable/opt/homebrew/opt/symlink on every run. Warns loudly when the ML venv is missing instead of silently skipping. - Dashboard showed "Idle" while Immich was processing (#28). The
/api/jobscall had a 2s timeout that caused intermittent failures under load, and errors were silently swallowed. Dashboard now shows the actual error when the API is unreachable, displays queue counts matching Immich's admin panel, and bumps the timeout to 5s.
Upgrade
brew upgrade immich-accelerator
immich-accelerator setup # if first time or new features require itImmich Accelerator v1.4.5
Fixes
- Database backups were silently 0 bytes (#24). Immich pipes
pg_dumpthroughgzip --rsyncable, which Apple's BSD gzip doesn't support.pg_dump_shim.jsnow reroutes those calls to Homebrew's GNU gzip (or strips the flag as fallback). The formula nowdepends_on "gzip"so fresh installs get GNU gzip automatically. - Watchdog could kill unrelated processes.
_kill_stale_processesmatched any command line containing the substringimmich. Replaced with precise patterns for the canonical worker (node … dist/main.js) and ML service (python -m src.main) launch shapes.
Test infrastructure
- Isolated E2E Immich stack (
scripts/e2e-stack.yml+e2e-stack.sh). Dedicated postgres / redis / api-only Immich server on port-shifted loopback addresses with throwaway state. The VM harness now requires this stack and refuses to run against prod Immich. - Real-data backup integration test that runs
pg_dump | gzip --rsyncablethrough the shim against the isolated Postgres and asserts the output is a valid non-empty pg_dump.
Upgrade
brew upgrade immich-accelerator
immich-accelerator setup # if first time or new features require itImmich Accelerator v1.4.4
Fixes
- Homebrew formula pulled node 25, breaking sharp on every fresh install: v1.4.x shipped with
depends_on "node"in the generated formula. Homebrew's defaultnodeformula tracks mainline (currently 25.x), but Immich 2.7.x pinsengines.node = 24.14.1andsharp@0.34.5's native addons fail to load on node 25 with aNODE_MODULE_VERSIONmismatch. Every freshbrew install immich-accelerator+immich-accelerator starthit an opaque worker crash atrequire('sharp')mid-Nest-bootstrap that looked like an Immich bug. Fix: pindepends_on "node@22"in the formula template and teachfind_node()to look under/opt/homebrew/opt/node@22/bin/node(keg-only — no/opt/homebrew/binsymlink). find_node()accepted unsupported node majors silently: previously it returned the firstnodebinary it found, regardless of version. Now filters toSUPPORTED_NODE_MAJORS = (22, 24)and installsnode@22if nothing compatible is present._rebuild_sharp()swallowed rebuild failures: loggedlog.errorand returned, letting the worker start and crash later with an unrelated-looking stack. Now raisesRuntimeErrorwith the rebuild stderr tail and a remediation pointing atbrew install node@22.
Upgrade resilience (catches future drift)
- Node preflight in
start: everyimmich-accelerator startnow re-resolves node viafind_node(), updatesconfig["node"]if the path changed, and compares against Immich'sengines.nodeparsed frompackage.json. Catches thebrew upgradedrift pattern where node silently jumps majors and breaks sharp, with a clear "install node@22" error before the worker ever spawns. - Sharp load preflight in
start: spawnsnode -e "require('sharp')"against the server dir. If it fails, auto-attempts a rebuild and retries. If the retry still fails, hard-errors with remediation. This turns "opaque worker crash 10+ seconds into Nest bootstrap" into a 1-second clearly-labeled check.
Test coverage
tests/test_fresh_install.py::TestNodeVersionPreflight— 11 new unit tests covering_node_major_version,find_nodeversion filtering,_check_node_engines_compatwith real stubbed node binaries,_verify_sharp_loadserror reporting, and a static check that the CI-generated Homebrew formula pinsnode@22.scripts/e2e-fresh-install.shstep 1b — assertsfind_node()on a real VM returns a node inSUPPORTED_NODE_MAJORS. Would have caught the v1.4.x regression on the first E2E run.scripts/e2e-fresh-install.shstep 3b — runs the full sharp preflight (_check_node_engines_compat+_verify_sharp_loads) against the extracted Immich server in the VM.scripts/e2e-fresh-install.shsteps 9–16 — real execution coverage: start ML inSTUB_MODE, hit/ping+/health+/predictfor actual JSON render (catches anyORJSONResponseregression), runimmich-accelerator ml-testagainst the stub, verify theNODE_OPTIONSpg_dump shim actually loads in a real node process, start the real worker and wait for theImmich Microservices is runningNest-bootstrap marker, run the dashboard against the live worker and confirmworker.alive=true, verify thestatussubcommand reports the running PID, verifystopcleanly terminates + is idempotent, verify a secondstartafterstopreaches Nest bootstrap again.scripts/e2e-bootstrap-vm.sh— installsnode@22instead of Homebrew-defaultnode, sets up the/buildsynthetic firmlink via dual/etc/synthetic.d/+/etc/synthetic.confentries (some macOS VM images only honor the legacy location), reboots the VM to activate the firmlink, and verifies/buildresolves post-reboot before saving the base snapshot. pip install now retries 3× on VM DNS flakes.
Upgrade
brew upgrade immich-accelerator
immich-accelerator setup # if first time or new features require itImmich Accelerator v1.4.3
Fixes
- NODE_OPTIONS shim path broken in v1.4.2 (#24 follow-up): The v1.4.2 commit that "polished" the pg_dump shim wrapping wrapped the path in single quotes, thinking Node would unquote them. Node doesn't — it splits
NODE_OPTIONSon whitespace and takes the literal characters. The quotes became part of the filename and every worker start failed withCannot find module ''/opt/homebrew/Cellar/…/pg_dump_shim.js''. Fix: wrap the path in double quotes, which is the only form Node'sNODE_OPTIONStokenizer honors universally (single quotes and backslash escapes both fail — both verified empirically against Node 25.2). Verified end-to-end against a real v1.4.2 brew install on an M4 Mac — shim loads,pg_dump (PostgreSQL) 18.3runs. - ORJSONResponse crash in ML service (#20 tail): The v1.3.4 commit dropped
orjsonfromml/requirements.txtwith an incorrect commit message claiming "not imported by our code."main.pyimportsORJSONResponsefromfastapi.responsesand uses it in 3 places, and FastAPI'sORJSONResponse.render()assertsorjson is not Noneat render time — every/predictrequest crashed withAssertionError: orjson must be installed to use ORJSONResponse. Fix: swap to stdlib-backedJSONResponse, keeping theorjsondrop (which was correct — its wheel broke Homebrew's dylib fixup). Verified end-to-end: ml-test passes 4/4 on real CLIP + OCR requests with no orjson in the venv.
Regression guards (test coverage the v1.4.2 VM E2E didn't have)
- Static check:
ml/srcusesORJSONResponseonly ifml/requirements.txtpinsorjson— would have caught the v1.3.4 half-fix instantly. - Real-node integration: generate the exact
NODE_OPTIONSstringcmd_startbuilds, spawnnode --requireagainst a sentinel shim, assert it loads. Would have caught the v1.4.2 quoting bug before merge. - Static check:
cmd_start's shim-path escaping uses backslash form, not shell quoting.
Upgrade
brew upgrade immich-accelerator
immich-accelerator setup # if first time or new features require itImmich Accelerator v1.4.2
Fixes
- Path-mismatch probe false positive (#19 follow-up): The v1.4.1 split-setup probe queried
/api/librariesas its primary signal, but that endpoint only returns external libraries in Immich 2.7+ — the upload library (where web-UI uploads land) is implicit atIMMICH_MEDIA_LOCATIONand doesn't appear there. Result: any install with an external library plus a correctly-setupload_mountgot blocked atimmich-accelerator startwith a false "path mismatch" error. The probe now parses an upload-library asset'soriginalPath(filteringlibraryId: null) and skips external-library assets entirely. If no upload assets exist yet, the check is skipped — nothing to compare against. - External library path validation: The probe now also checks every external library's
importPathagainst the Mac filesystem. Missing paths produce a non-fatal warning per library with the library name and guidance to mount or synthetic-link them. Upload-library mismatch remains fatal (thumbnails WILL 404), external-library inaccessibility is advisory (worker can still process uploads + any libraries whose paths do resolve). - pg_dump ENOENT on database backup (#24): Immich's
DatabaseBackupServicehardcodes/usr/lib/postgresql/${version}/bin/pg_dumpin its dist, and on macOS that path doesn't exist, so the native microservices worker fails every backup cycle with ENOENT./usr/lib/is SIP-protected and there's no env-var escape hatch in Immich's code. Fix: a tiny Node runtime shim (immich_accelerator/hooks/pg_dump_shim.js) that monkey-patcheschild_process.spawn/spawnSync/execFileto rewrite the Linux postgres client path to/opt/homebrew/opt/libpq/bin/at call time. The shim is preloaded viaNODE_OPTIONS=--require …when we launch the worker. Immich's JS source on disk is never touched — the same interposition pattern we already use for the ffmpeg wrapper, applied at the Node module layer. Verified end-to-end on a real Mac with node + libpq 18.3.
Docs
- Split deployment clarity: Reworked the Split deployment section of the README to lead with the one requirement everyone needs to get right — both machines see the same files at the same absolute paths via a shared filesystem (NFS/SMB). There is no HTTP transport of thumbnails between hosts; the worker reads/writes directly to disk. Surfaced because a v1.4.1 user interpreted "match paths" as string matching. Also dropped the long-stale v0.x and v1.2.x migration sections.
Test infrastructure
- VM bootstrap script: Fixed three edge cases that kept the tart-based E2E harness from running cleanly — trap composition bug that left stale VMs behind, stdin-race on heredoc-over-ssh that silently dropped pip install commands, and
brew updatenetwork flakiness aborting bootstrap. The harness is now proven end-to-end against live Immich.
Upgrade
brew upgrade immich-accelerator
immich-accelerator setup # if first time or new features require itImmich Accelerator v1.4.1
Fresh-install fixes
- Dashboard ModuleNotFoundError (#17): Homebrew formula wrapper now runs the CLI under the ML venv's Python instead of stock
python@3.11. The dashboard's lazyfastapi/uvicornimports now resolve on any fresh Mac — previously they only worked if the user happened to have the packages installed globally. Also added abrew testblock that force-loadsdashboard.create_appso this class of bug gets caught at audit time, not in the wild. - Missing corePlugin on OCI download (#18): Re-fix of a regression from the v1.3.3 fix. The layer loop had a
size_mb < 1early-break shortcut that fired before examining the current layer — stranding the tiny corePlugin COPY layer. Replaced with a version-aware break (_has_everything) that requirescorePlugin/manifest.jsonfor Immich 2.7+. Verified end-to-end against a live ghcr.io pull.
Test coverage
- Added
tests/test_fresh_install.py— unit tests for the layer-break logic, a static check thatfastapi/uvicornstay pinned inml/requirements.txt, an AST check thatdashboard.pyhas no top-level third-party imports, and a slow integration test that builds a pristine venv and confirmscreate_appworks with onlyfastapi+uvicorninstalled. - CI now runs on macOS 14 (Apple Silicon) in addition to Ubuntu. The
fresh-install-macosjob catches "works on my machine" bugs before shipping.
Upgrade
brew upgrade immich-accelerator
immich-accelerator setup # if first time or new features require itImmich Accelerator v1.4.0
- libpq as Homebrew dependency:
psqlnow installed automatically viadepends_on "libpq"in the formula — works for both new installs and upgrades, not just setup. - Published GitHub releases: Releases are now published automatically (not draft).
Upgrade
brew upgrade immich-accelerator
immich-accelerator setup # if first time or new features require it