An artifact that can't be written
Every stage reports ✓ and no book lands. Keystone builds into scratch space
and moves the finished file into artifacts/ as its last act, so this failure
arrives after the build itself has succeeded.
What it looks like
Publishing target: 'book' | format: pdf
✓ Preparing your artifact 1.5s
✓ Typesetting (pass 1) 22.1s
✓ Typesetting (pass 2) 19.8s
✓ Typesetting (pass 3) 16.5s
mv: cannot create regular file 'artifacts/my-project-book-20260101.pdf': Permission denied
ERROR: publishing failed while promoting the artifact to
artifacts/my-project-book-20260101.pdf
See https://keystone.knight-owl.dev/errors/artifact-not-written/
The ERROR: is the same every time. The mv: line above it carries the reason:
mv: cannot create regular file 'artifacts/…': Permission denied
mv: inter-device move failed: '/tmp/…' to 'artifacts/…'; unable to remove target: Read-only file system
mv: error writing 'artifacts/…': No space left on device
mv: cannot create regular file 'artifacts/…': No such file or directory
A strict build reaches the same all-✓ shape by another
route and stops with and the build produced warnings: instead. That one lists
the warnings that stopped it.
What it means
The book built, and artifacts/ would not take it.
The line above the ERROR: is the one to read: that is the operating system
refusing the write, quoted by mv. Nothing is staged for recovery, so clear the
obstruction it names and build again.
The directory isn't writable by you
Permission denied. artifacts/ exists, and the user the build runs as cannot
write to it. Builds run as
your own user and never as root,
so a directory owned by somebody else stays closed — one Docker created for
itself because artifacts/ was missing when a container started, one left
behind by a build run under sudo, or one copied from another machine with its
ownership intact.
Take the directory back
chmod u+w artifacts restores a cleared write bit. Where another user owns
the directory, sudo chown -R "$(id -u):$(id -g)" artifacts hands it back.
The filesystem is read-only
Read-only file system. Nothing here can be written, whatever the permissions
say: a project opened from a mounted disk image, a read-only network share, or
container wiring edited to mount artifacts/ :ro.
The move is always across filesystems, because scratch space is in memory and
artifacts/ is on disk. inter-device therefore describes every promotion, and
the fault is the reason at the end of the line.
Build somewhere writable, or put the mount back
Copy the project onto a disk you can write to. Where the mount is the cause,
restoring .docker/docker-compose.yaml — from git, or from a fresh copy of
your template — drops the :ro. That file is
the engine's to own,
so nothing of yours goes with it.
The disk is full
No space left on device. The disk holding your project has no room for the
book.
The move had already begun, so artifacts/ holds a truncated file under the
name a finished book would carry. It opens as a damaged document, if at all.
Clear the artifacts you no longer need
make clean empties artifacts/, which is often enough on its own: a build
names its output for the day it ran, so nothing is overwritten from one day
to the next. Empty the directory rather than deleting it — see
The directory was recreated. Where the space
went elsewhere, free it there.
The directory was recreated
No such file or directory. Deleting artifacts/ and letting the next build
recreate it leaves Docker serving the container the deleted directory. Listing
it works, so the build finds an artifacts/ and only the write fails.
It comes and goes: catching the stale directory is a race, so the same project can fail once and publish the next time.
Empty artifacts/, never delete it
make clean empties it in place and cannot cause this. Where it has already
happened, another build or two picks up the real directory — nothing is wrong
with the project.
Related
- Publishing your book — where artifacts land, and how a build reports its stages.
- Project anatomy — what lives in
artifacts/, and what the engine owns. - Sandboxing — why
artifacts/is the only writable path you own.