TL;DR: The COPY source pattern matches nothing in the build context. Check that the files exist relative to the build context root (not relative to the Dockerfile), that a .dockerignore is not excluding them, and that the pattern spelling matches. Nine times out of ten the build context is a different directory than you think, or .dockerignore swallowed the file.

## The error

```text
COPY failed: no source files were found
```

## Fix it

1. Check what is actually in the build context. List the directory you pass to `docker build` (the PATH argument, often `.`):
   `ls` in that directory, or `docker build` with the right context.
   Expected: the files you want to COPY are present there.
2. Inspect .dockerignore in the context root:
   `cat .dockerignore`
   Expected: no rule excluding your files. Watch for broad rules like `*` or `*.log` with too few `!` exceptions.
3. Fix the Dockerfile path or the build invocation, whichever is wrong:
   - If files are elsewhere: `docker build -f path/to/Dockerfile /correct/context/dir`
   - If the pattern is wrong: COPY paths are relative to context root, so `COPY app/src /app` needs `app/src` under the context, not under the Dockerfile dir.
4. Rebuild.

## When this applies
- COPY/ADD with a glob or path that matches zero files
- Builds run from CI where the checkout directory differs from local

## When this does NOT apply
- Error names the file and mentions .dockerignore explicitly (that is the ADD variant; same family, adjacent fix)
- "failed to read dockerfile" (the Dockerfile itself is missing from context)
- Permission errors during COPY (different failure)

## Versions
All Docker Engine versions, classic builder and BuildKit. BuildKit phrases it identically.

## Why it happens
COPY sources resolve against the build context, not the Dockerfile location. Running `docker build -f docker/Dockerfile .` with `COPY src /app` looks for `./src`, not `docker/src`. A second classic is .dockerignore excluding the file, which removes it from the context before COPY runs, so the pattern matches nothing.

## Edge cases
- Trailing-slash semantics: `COPY src/ /app/` copies contents; `COPY src /app` copies the dir. Both fail the same way when src is missing.
- Symlinks pointing outside the context are not followed; COPY sees nothing.
- Windows line endings in .dockerignore can silently break exception rules.
