Summary
This incident centers on a long‑standing workflow for deploying a universal Emacs site-start.el across multiple machines. The approach—placing a shared initialization file somewhere on the default load-path—breaks under Snap-packaged Emacs 30.2 on Ubuntu 24.04, because Snap’s confinement model prevents modifying or extending directories inside the Snap environment. As a result, the expected multiuser initialization mechanism no longer works.
Root Cause
The failure stems from Snap confinement and read‑only mount behavior, which fundamentally changes how Emacs discovers system-wide initialization files.
Key contributing factors include:
- Snap packages mount their filesystem read-only, preventing edits even with
sudo. - Snap restricts access to system directories, so
/usr/local/share/emacs/site-lispis not on the defaultload-path. - Emacs inside Snap only sees paths inside
/snap/..., including its own immutablesite-start.el. - The traditional multiuser site-init workflow assumes writable system paths, which Snap explicitly forbids.
Why This Happens in Real Systems
This pattern is common when traditional Unix workflows meet modern sandboxed packaging systems.
Typical systemic causes:
- Security-first packaging models (Snap, Flatpak, AppImage) isolate applications from the host filesystem.
- Legacy software expects FHS-compliant directory layouts, which sandboxed apps do not provide.
- Multiuser configuration mechanisms were designed before containerized packaging existed.
- System administrators assume root can modify everything, which is no longer true under confinement.
Real-World Impact
This mismatch leads to practical operational issues:
- Shared configuration cannot be deployed using standard Emacs site-init mechanisms.
- Automation scripts break because expected directories are missing.
- Multiuser environments lose consistency, forcing per-user
.emacsfiles. - Maintenance overhead increases, especially for teams managing many VMs.
- Debugging becomes harder, since Emacs behaves differently depending on packaging method.
Example or Code (if necessary and relevant)
Below is an example of how a Snap-packaged Emacs reports its load-path, illustrating the confinement:
(prin1 load-path)
How Senior Engineers Fix It
Experienced engineers recognize that Snap’s constraints require changing the deployment model, not fighting the sandbox.
Common solutions:
- Stop using the Snap version of Emacs and install via:
apt install emacsppa:kelleyk/emacs- Building from source
- Use EMACSLOADPATH (not EMACSINIT) to prepend shared directories:
- Works without modifying Snap internals
- Can be set system-wide via
/etc/environment
- Package the shared site-start.el as an Emacs package, then:
- Install it into each VM’s user or system package directory
- Autoload it via
early-init.el
- Use a wrapper script that sets environment variables before launching Emacs
- Adopt a configuration management tool (Ansible, Puppet, Nix) to deploy consistent configs across machines
The key insight: you cannot modify the Snap environment, so you must move the configuration outside it.
Why Juniors Miss It
Less experienced engineers often assume:
- Root access overrides all restrictions, which is not true under Snap.
- All Emacs installations behave the same, ignoring packaging differences.
- load-path is always writable or extendable, which fails under confinement.
- The traditional Unix filesystem layout still applies, even when sandboxing changes everything.
They also tend to focus on fixing the symptom (missing load-path entries) rather than understanding the architectural constraint (Snap isolation).