Linkwarden 1.21.1: monolith snapshots fail with spawn monolith EACCES
-
Ahoi! Ive run into an issue setting up linkwarden. Looked like no local copies of links could be created. I investigated with AI and found a permission issue. Tested the fix locally and it works. Here is the full report and patch (by Claude Opus4.7):
Symptom
For every bookmark you save, Linkwarden's worker creates four offline snapshots in the background and stores their paths on the link record:
image(PNG screenshot),pdf,readable(extracted plain-text/JSON), andmonolith(full self-contained HTML archive — the actual offline copy of the page, with images/CSS/JS inlined asdata:URIs). When a snapshot fails the corresponding field is set to the literal string"unavailable".On
app.linkwarden.cloudronapp@1.21.1the first three always succeed, but every link ends up withmonolith: "unavailable":GET /api/v1/links/14 { "id": 14, "url": "https://example.com/", "image": "archives/1/14.jpeg", "pdf": "archives/1/14.pdf", "readable": "archives/1/14_readability.json", "monolith": "unavailable", "lastPreserved": "2026-04-30T12:41:57.614Z" }In effect, the most useful preservation format — the offline HTML archive — is missing from every saved bookmark, while the UI just shows "unavailable" without surfacing why.
Worker logs show the underlying error:
Error: spawn monolith EACCESSource:
apps/worker/lib/preservationScheme/handleMonolith.tscallsspawn("monolith", …), which relies on the binary being resolvable throughPATHfor the worker process.Root cause
The
monolithbinary is installed viacargo install --locked monolithin theDockerfile. Cargo defaults to$CARGO_HOME/bin, which during the build is/root/.cargo/bin. The base image keeps/rootat mode700, and the runtime worker runs ascloudron(UID 1000) — so even though the binary itself is-rwxr-xr-x,cloudroncan't traverse/rootto reach it.Reproduce inside a 1.21.1 container:
$ ls -ld /root drwx------ 1 root root 4096 Apr 23 02:20 /root $ ls -la /root/.cargo/bin/monolith -rwxr-xr-x 1 root root 12384776 Apr 23 02:22 /root/.cargo/bin/monolith $ runuser -u cloudron -- /root/.cargo/bin/monolith --version runuser: failed to execute /root/.cargo/bin/monolith: Permission denied/rootis on the read-only image layer, sochmod o+x /rootat runtime is also rejected. This is purely a packaging issue — the binary is fine, just unreachable.Fix
One-line change in the
Dockerfile: pass--root /usr/localtocargo installso the binary lands in/usr/local/bin/monolith, which is on the defaultPATHand traversable for everyone.-# install rust and monolith (/root/.cargo/bin/monolith) +# install rust and monolith +# install monolith into /usr/local/bin so it is reachable for the runtime +# `cloudron` user (UID 1000); /root is mode 700 in the base image and would +# otherwise hide /root/.cargo/bin/monolith → spawn EACCES in the worker. RUN curl https://sh.rustup.rs -sSf | bash -s -- -y ENV PATH="/root/.cargo/bin:${PATH}" -RUN cargo install --locked monolith +RUN cargo install --locked --root /usr/local monolithFull patch attached:
linkwarden-monolith-eacces.patch(3 files, +9/−3 — Dockerfile + CHANGELOG entry + CloudronManifest version bump 1.21.1 → 1.21.2).I'd happily open a merge request directly, but I don't have a
git.cloudron.ioaccount — feel free to apply the patch withgit am linkwarden-monolith-eacces.patch(or just take the diff).Verification
Verified the fix on a running 1.21.1 container by approximating the post-patch state at runtime:
cp /root/.cargo/bin/monolith /app/data/bin/monolith(writable persistent volume)- Prepend
/app/data/binto the worker'sPATHvia a tinyNODE_OPTIONS=--require …shim (necessary becausedotenv-cliwon't overwrite an already-setPATH) - Restart the app
After that, a freshly created link preserves correctly:
{ "id": 15, "url": "https://en.wikipedia.org/wiki/Monolith_(file_archive)", "monolith": "archives/1/15.html", "image": "archives/1/15.jpeg", "pdf": "archives/1/15.pdf", "readable": "archives/1/15_readability.json" }The resulting HTML is 600 KB and embeds data URIs as expected from monolith. Pre-existing "unavailable" links can be brought back with the
Re-preserve all brokenadmin action.Possibly related
Topic #13640 ("Missing HTML saved version and cookie popup in screenshots") describes the same observable symptom and was tentatively diagnosed as a resource issue. Based on the reproduction above I believe this
EACCESis the actual underlying cause for the missing HTML snapshots.
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login