Dev.to WebDev 🛠 Dev 👁 0 📖 6 min read

SCP "Not a Regular File": What It Means and How to Fix It

If scp stops with something like scp: /remote/project: not a regular file, the source path usually resolves to a directory that you're trying to copy without recursive mode. The fix depends on what you actually meant to

If scp stops with something like scp: /remote/project: not a regular file, the source path usually resolves to a directory that you're trying to copy without recursive mode.

The fix depends on what you actually meant to copy — the whole directory, or just one file inside it. Both are one-command fixes. Here's how to tell which one you need, followed by what to check if it's still not working.

Quick answer

Add -r if you want the whole directory: scp -r user@server:/remote/project . If you only wanted one file from inside it, fix the path instead: scp user@server:/remote/project/file.txt .

SCP "is a directory" error

If SCP returns scp: ~/: is a directory, the source path resolves to a directory rather than a regular file. If you meant to copy that directory, add -r:

scp -r user@server:~/ .

If you meant to copy a single file, replace ~/ with the path to that file. The ~/ path means the current user's home directory, so plain scp cannot treat it as one regular file. Recursive mode with -r tells SCP to descend into the directory and copy its contents.

What "not a regular file" means

Unix-like systems classify filesystem entries by type. A regular file is what most people mean by "a file" — text, a binary, an image, anything with byte content you can read start to end. A directory is a different type entirely: a listing of other entries, not a stream of bytes. Symlinks and device/special files are different types too, but they're not what's usually going on here.

By default, scp does not recursively copy directories. If the source path is a directory and you try to copy it without -r, scp can stop with a not a regular file error instead.

This is a type problem, not a permissions problem. Don't reach for chmod or sudo here — they won't do anything, because the issue isn't who can read the path, it's what kind of filesystem entry it is.

Check whether the source is actually a directory

If you're not sure, ask before guessing. Locally:

ls -ld /path/to/thing

On the remote host, run the same check over SSH without opening an interactive session:

ssh user@server 'ls -ld /remote/path'

The first character of the output tells you the type: a d means directory, a - means regular file.

drwxr-xr-x  5 user user  4096 Sep  3 09:14 project
-rw-r--r--  1 user user  1820 Sep  3 09:14 file.txt

project is a directory, so plain scp will refuse it. file.txt is a regular file, so it'll copy fine as-is.

You want the directory: use scp -r

-r tells scp to recurse: instead of trying to copy one object, it walks the directory tree and copies every file and subdirectory it contains, recreating the structure at the destination. That's the entire reason the flag exists — a directory isn't a single stream of bytes, so it can't be handled the same way a regular file is, and scp needs to be told explicitly to traverse it.

Remote directory to your local machine:

scp -r user@server:/remote/project .

Local directory to a remote server:

scp -r ./project user@server:/remote/path/

Both forms work the same way regardless of which side — local or remote — the directory happens to be on. Add -r to the same command you already had; nothing else about the syntax changes.

The directory itself vs. what's inside it

These two commands are not the same:

scp -r ./project user@server:/destination/
scp -r ./project/* user@server:/destination/

The first copies project as a folder, so you end up with /destination/project/.... The second expands the wildcard locally, before scp ever runs, and copies each item inside project directly into /destination/ — no wrapping folder. If you use the second form, keep in mind that in most shells * doesn't match dotfiles, so hidden files like .env or .gitignore would silently get left behind. Pick whichever layout you actually want at the destination.

You only wanted one file: fix the path instead

Not every "not a regular file" error means you need a directory. If you were trying to grab one specific file and got this error, you probably pointed scp at the containing folder instead of the file itself. Point it at the file directly:

scp user@server:/remote/project/file.txt .

No -r needed — that flag is only for directories. Adding it here wouldn't cause harm, but it's not what fixes anything if the actual issue is that the source path is one level too high.

This is really the whole decision tree for this error: figure out whether you wanted the directory or a file inside it, then either add -r or correct the path. Everything past this point is about what to check if you've already made the right choice and it's still failing.

scp -r still fails — what to check

The path is wrong, not just missing -r

A typo, a path that's one directory level off, or a source that doesn't exist on the remote host can all produce confusing errors. Re-run the ls -ld check above against the exact path in your command — not the path you meant to type — to confirm it points where you think it does.

Check that source and destination are in the right order

scp takes the source first and the destination last, same as cp. If you accidentally reversed them — easy to do when one side is remote and one is local — the command is operating on a different path than you intended. Check the exact source path with ls -ld before changing anything else.

A wildcard pulled in a directory you didn't expect

If your command uses a local glob like scp ./project/* user@server:/destination/, remember that * expands to everything in that folder — files and subdirectories alike. If any subdirectories are mixed in with the files you meant to grab, plain scp will stop on the first one it can't handle as a regular file. Either add -r if you're fine copying those subdirectories too, or narrow the wildcard so it only matches files.

The next error is a permissions or authentication problem

Once the path and recursion are both correct, a different failure — like Permission denied — means you've moved past this error into a separate issue. If it's a filesystem permissions problem on the destination or source, see our guide to SCP permission denied errors. If SSH itself won't authenticate before the transfer even starts, that's covered in SSH permission denied (publickey).

A note on modern OpenSSH

Starting with OpenSSH 9.0, scp uses the SFTP protocol for transfers by default instead of the older scp/rcp protocol; the legacy protocol is still available with the -O flag if you need it for compatibility with an older server. This mainly changes things like wildcard handling and quoting behavior — it doesn't change the underlying idea that scp needs -r to descend into a directory. If you're troubleshooting on a very old system still running the legacy protocol by default, the same diagnosis and the same fix apply either way.

Quick reference

Situation Command
Copy a remote directory to local scp -r user@server:/remote/project .
Copy a local directory to remote scp -r ./project user@server:/remote/path/
Copy one file from inside a remote directory scp user@server:/remote/project/file.txt .
Check if a path is a directory ssh user@server 'ls -ld /remote/path'

Diagnostic summary

scp: ... not a regular file means the path you gave scp is a directory, and plain scp only transfers regular files. If you want the whole directory, add -r and copy it in the direction you need — remote to local or local to remote. If you only wanted one file, correct the path so it points at that file directly instead. If -r is already in place and it's still failing, the next thing to check is usually the path itself, argument order, a wildcard pulling in extra directories, or a separate permissions/authentication error further down the line.

Originally published on SSHFlow.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.