catkin_make dies mid-configure with Permission denied the moment CMake tries to write a .tmp file under build/ or devel/, and every run after that fails at the same spot. The stack trace points at configure_file, catkin's macro files and a Python helper, which makes it look like a catkin bug. It is not: errno 13 means the kernel refused a write because the directory belongs to another user — in practice almost always root, left behind by an earlier build that ran with sudo. This guide decodes the two error shapes, shows the two-command check that confirms the cause, walks through the chown plus clean reconfigure that fixes it, and lists the rarer causes so you can rule them out with the same commands.
What errno 13 is telling you
catkin fails in two shapes, and both are the same event. CMake prints 'Could not open file for write in copy operation' on a path ending in .tmp inside build/ or devel/, raised by configure_file from catkin's em_expand and catkin_package macros. Helper scripts print the same failure as a Python IOError: [Errno 13] Permission denied — for example when order_paths.py cannot write ordered_paths.cmake into the build tree.
errno 13 is EACCES: the kernel refused the operation because of ownership or permission bits. It is not errno 2, ENOENT, a missing path, and not errno 28, ENOSPC, a full disk. The .tmp suffix is the tell: CMake stages the write through a temporary file, so the message names a file that does not exist yet. The real problem is that your user cannot create anything in that directory. Reading still works, which is why the build gets partway through configure before it stops.
How build and devel end up owned by root
Work down this list in order; the first cause covers most cases:
- An earlier build ran with sudo. sudo catkin_make or sudo make executes the whole toolchain as root, so every cache entry and generated file lands owned by root. One run is enough to poison build/ and devel/.
- The workspace was created as root. Sources unpacked with sudo, a tree copied to the board by a root login, or a disk image prepared as root leave root-owned directories that your first build inherits.
- Another account built in the same path. Shared boards collect logins; whoever built last owns the generated trees.
- Mixed history. A workspace that has seen both sudo and user builds ends up with interleaved ownership, so the failure moves around between runs with no obvious pattern.
The error text never says 'root' — you infer it from the ownership columns in the next step.
Confirm the cause before changing anything
Run both commands from the workspace root:
ls -ld build devel
find . -not -user $USER
A healthy workspace lists your own login in the owner and group columns of both directories, and find prints nothing at all. If ls shows root root, or find lists files under build/ and devel/ owned by root, you have your answer. The same checks, plus two more, separate every cause covered here:
| Symptom | What it means | Test |
|---|---|---|
| ls shows root root | a sudo build or a root-owned copy created the tree | the chown fix below |
| find lists only some files | mixed ownership from repeated sudo runs | the same fix; chown -R catches all of them |
| findmnt . shows ro | filesystem remounted read-only, often after media errors | read dmesg before remounting; a failing card keeps degrading |
| errno 28, No space left on device | full disk, not a permissions problem | df -h ~, then free space |
If ls -ld already shows your own login and the error still stands, skip to the causes further down — but in practice the ownership check settles it.
Fix: chown the workspace, then reconfigure clean
Four steps, in order:
- Stop any running build so nothing holds files open in build/.
- Hand the whole tree back to your login:
sudo chown -R $USER:$USER ~/catkin_ws. On distributions where the group name differs from the user name, usesudo chown -R $(id -u):$(id -g) ~/catkin_wsinstead;id -gnprints your group name. - Delete the generated trees and reconfigure from scratch:
cd ~/catkin_ws && rm -rf build devel install && catkin_make. After step 2 the deletion needs no sudo. The clean reconfigure is deliberate: a half-written CMakeCache.txt from the failed runs is exactly the leftover state that keeps builds flaky, and the same start-from-a-known-state discipline that clears up flaky 3D camera tests applies here. - Verify before you trust it:
find ~/catkin_ws -not -user $USERmust print nothing, andls -ld build develmust list your login in both owner columns.
That is the whole fix; the build that died at configure_file now walks past it.
Read the permission bits behind the error
A failing directory typically lists as drwxr-xr-x root root. The mode string is three permission triads, each worth one digit:
Root, as owner, holds rwx. Your account falls in the group or other triads and holds r-x: read and enter, but not write. Creating any file — including every .tmp that configure_file needs — requires write permission on the directory, which is why the build reads everything happily and dies at the first creation. After the chown you are the owner, your triad returns to 7, and the identical commands succeed unchanged.
When ownership is not the cause
Four alternatives, each with its test:
- A filesystem without ownership. Workspaces on USB sticks or card readers formatted FAT32 or exFAT carry no POSIX owner or mode bits, so chown has nothing to change and symlinks fail; build on an ext4 filesystem instead.
-
The immutable flag.
lsattr build/CMakeCache.txtprinting an i in the attribute string means even root cannot modify the file;sudo chattr -i <file>clears it. Rare, and it usually follows an unusual recovery attempt. -
A shared board with several logins. Two engineers rebuilding the same path will keep re-breaking each other's trees. Fix it with a group, not sudo: put both accounts in one group, apply
chmod -R g+wto the tree, and set the setgid bit on every directory withfind . -type d -exec chmod g+s {} +so new files inherit the group. - A workspace on a network mount. NFS often maps root to an unprivileged id, so sudo writes behave differently than on a local disk and ownership fixes may not stick; keep workspaces local.
Read-only mounts and full disks fail with different signatures — findmnt showing ro, or errno 28 rather than 13 — so the table above separates them from this fix.
Build in the cell without running sudo
The same trap repeats on dedicated hardware: you log into a cell-mounted controller with an administrator account, build the vision stack that drives the 3D sensors and cameras, and the runtime account later inherits a tree it cannot write. Decide the build account when you set the machine up, keep the workspace in that account's home, and deploy through the install space rather than writing into system paths with sudo. The commands are identical on a desk machine and on a controller; only the owner of the path changes. If the controller runs a Linux image, treat its accounts exactly like a desktop's.
Two vision controllers from the range that suit that role:
- LAN ports
- 3-4 LAN ports
- USB 3 ports
- 2 USB 3 ports
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
Match the controller to your camera count, then step through the configurator to size storage and memory around your build and runtime load. If you would rather keep the toolchain off the production machine entirely, fanless industrial mini PCs make a quiet build box that never touches the cell.
Keep it fixed
Three habits prevent a repeat:
- Build only as the workspace's owner. Installing a system library with your package manager under sudo is fine; exit the root shell before catkin_make runs.
- Give each workspace path one owner, and use a shared group only where a tree is genuinely shared.
- After any suspicious sudo use, run the find command from the fix — thirty seconds of checking against an afternoon of rebuilding.
Permission failures rarely travel alone, so keep the neighbouring guides at hand: C++ camera SDK linking errors and -fPIC relocation errors when configure passes but the link stage fails; Linux vision shared library errors when it builds but will not start; fixing camera SDK build errors after a library upgrade when versions moved underneath you; and on ARM boards, CMake Boost targets undefined is the sibling configure-time failure. If the built program then cannot open the camera, camera SDK cannot find device covers the access side of the same coin. The systems topic page collects the rest.
If a configure log still refuses to make sense, send it to us through the contact page — expert support comes free with every order, and the fix is usually one command away.
Questions
Why does one sudo build break every later catkin_make?
sudo runs the whole toolchain as root, so configure_file output, generated CMake package files and the cache all land on disk owned by root. Your next build runs as you and must overwrite those files, which the kernel refuses with errno 13. A single sudo make is enough to poison build and devel; the cure is chown plus a clean reconfigure, not more sudo.
Can I just run everything with sudo instead?
It looks faster and it is the wrong trade. A sudo build uses root's environment, so PATH-based tool selection and library search can differ from your normal shell and produce different results. It also scatters root-owned output that editors, debuggers and later user builds cannot touch. Keep the build in your account and use the install space when a file deliberately must land outside your home directory.
Does chown change anything inside the files?
No. chown changes ownership metadata only; contents, permissions and timestamps stay exactly as they were, so it is safe across a source tree with uncommitted work. The exception worth knowing: on an NFS mount with root_squash enabled, root's write is mapped to an unprivileged id, so an ownership fix may not stick. Keep workspaces on a local filesystem and the fix is permanent.
How do I check the whole home directory for root-owned files?
Run find /home/yourusername -not -user yourusername. It lists every file and folder the account does not own; a clean home prints nothing. Add -ls for a detailed listing, or pipe through head when the tree is large. Run it once after the chown as verification, and again whenever you suspect a build slipped through under sudo.
Should build and devel be committed to version control?
No. Everything in build, devel and install is generated: configure and make rewrite it on every run, so committing it bloats the repository and recreates the ownership conflict on every fresh checkout under a different account. Keep src and your version-control metadata, ignore the rest, and let catkin_make regenerate it on demand.

