Solving the 'Text file busy' Error When Updating Linux Binaries

beginner๐Ÿง Linux2026-07-09| Linux (Ubuntu, Debian, CentOS, RHEL, Arch) using standard filesystems like Ext4 or XFS.

Error Message

cp: cannot create regular file '/usr/local/bin/app': Text file busy
#linux#sysadmin#devops#troubleshooting#bash

The Problem ScenarioImagine you are deploying a fresh build of a Go service or a C++ tool to your production server. You run a standard copy command to overwrite the old binary:

cp /tmp/new_version /usr/local/bin/app

Instead of a clean update, your terminal spits out a frustrating error:

cp: cannot create regular file '/usr/local/bin/app': Text file busy

Linux triggers this protection because the kernel refuses to let you modify a binary's contents while a process is actively executing it. If the kernel allowed a mid-execution overwrite, the running application would likely crash or encounter memory corruption as the underlying code changed beneath it.

Step 1: Identify the Locking ProcessTo fix the lock, you first need to hunt down the process holding the file. Two main tools make this easy.

Using fuserThe fuser utility identifies which processes are using a specific file or directory. It is often the fastest way to get a PID.

fuser /usr/local/bin/app

You might see output like this:

/usr/local/bin/app:  4812e

In this example, 4812 is the Process ID. The e suffix tells you the file is being used as an executable.

Using lsofIf you need more context, such as the user or the specific command name, use lsof (List Open Files):

lsof /usr/local/bin/app

This provides a detailed table showing the process name, the user, and the file descriptor type.

Step 2: The Manual Approach (Stop and Replace)The simplest approach is often the 'nuclear' option: stop, swap, and restart. This is safest for applications that don't handle hot-reloading well.

  • Terminate the process: kill 4812- Verify it has stopped, then copy your new version: ``` cp /tmp/new_version /usr/local/bin/app
### The 'rm' StrategyInstead of using `cp`, which tries to open the existing file and truncate it, use `rm` first:

rm /usr/local/bin/app cp /tmp/new_version /usr/local/bin/app


When you `rm` a running binary, the file's entry is removed from the directory. However, the actual data stays on the disk as long as the process is running. The new `cp` command creates a completely new inode. Existing processes keep running the old code in memory, while any new launches will use the new version.
### The 'install' CommandThe `install` command is the professional way to handle this in one shot. It automatically unlinks the destination before copying.

install -m 755 /tmp/new_version /usr/local/bin/app


This is standard practice in many Makefile and CI/CD pipelines because it avoids the 'busy' error entirely.
## Step 4: Managing via SystemdFor production services managed by `systemd`, you should wrap the update in a restart logic. This ensures your logs and child processes stay clean.

sudo systemctl stop my-app sudo install -m 755 /tmp/new_version /usr/local/bin/app sudo systemctl start my-app


## VerificationConfirm the update was successful by checking the file metadata and the process state:
- Verify the timestamp: ```
ls -l /usr/local/bin/app
```- Check the version string: ```
/usr/local/bin/app --version
```- Look at the process map: ```
ls -l /proc/$(pgrep app_name)/exe
``` If the symlink points to the path but includes `(deleted)`, the process is still running the old version of the file you unlinked. A restart is required to switch to the new code.

Related Error Notes