# Docker invalid file request in CI

> Docker invalid file request is the context transfer protocol losing track of a file, not a path permission or an escape from the build context.

Source: https://latchkey.dev/learn/docker/docker-invalid-file-request-path-in-ci  
Updated: 2026-09-21

Docker invalid file request is the receiving half of the build context transfer saying it was asked for a file it has no record of. It is a protocol bookkeeping failure between two processes, which is why nothing in the message names a permission, a pattern or a path outside your context, and why the usual advice about escaping the context does not apply.

## What this error means

A build fails during the internal step that loads the build context or the build definition, with a short message containing the words invalid file request followed by either a path or a bare number. No instruction has run. The failure is often platform specific and often disappears on a different machine or a different Docker version, which is the tell that it is a transfer problem rather than a content one. The block below is assembled from the two format strings, not captured from a run.

```Reconstructed from the two format strings in the file transfer receiver
--- the receiver was asked for a path it never announced
error: failed to solve: invalid file request test2/hello.txt
--- and the other form, where data arrived for an identifier with no open pipe
invalid file request 41
```

## Common causes

### The two sides disagree about how a path is written

The table is keyed by the path string as the sender wrote it, so any difference in separators, normalization or encoding between announcement and request makes the lookup miss. This is why the reports cluster on Windows and on nested directories, where path handling differs most between the halves.

### The same path was requested twice

The entry is deleted once a request has been issued for it, so a second request for the same path finds nothing and produces the path form of the message. Any duplication in the writer's work queue, from a hard link or a repeated entry, can reach this.

### Data arrived for an identifier that was already finished

The numeric form. A data packet routed to an identifier with no pipe open means the receiver has already closed that file or never opened it. It is the same disagreement seen from the other end of the exchange.

### A Docker or BuildKit version whose transfer has a path handling bug

Given the mechanism, a version difference is a genuine and common answer here in a way it is not for most build errors. In our experience the first useful experiment is a different version rather than a different Dockerfile, which is unusual enough to be worth saying out loud.

## How to fix it

### Establish whether it is your tree or your build environment

1. Build the same context on a different host platform, or with a different Docker version.
2. If it transfers cleanly, the tree is fine and the answer is a version or a platform difference.
3. If it fails everywhere, narrow the context by halves until the failure stops, and look at what you removed.

```Terminal
docker buildx build --progress=plain -t acme/api:ci . 2>&1 | tail -40
```

### Shrink what has to be transferred at all

Most contexts are far larger than the build needs, and every entry is one more chance for the two sides to disagree. An allowlist ignore file cuts the transfer to what you named, which is both faster and less exposed to this class of failure.

```.dockerignore
# .dockerignore
*
!src/
!package.json
!package-lock.json
```

### Do not reach for the context escape fixes

A named additional context and a widened context root are the right answers to the content hash error, and they will not touch this one. If your message is the checksum one rather than this one, follow the page linked below instead; if it really is this one, changing where the context root sits does not address the mechanism.

```Terminal
# this is the fix for the OTHER error, not for this one
docker buildx build --build-context shared=../shared -t acme/api:ci .
```

### Report it with the platform, the version and the tree shape

Because the useful variable is usually the environment, a report that names the host platform, the Docker and buildx versions and the shape of the directory that failed is worth far more than one that names your Dockerfile. The existing reports were fixed on exactly that kind of information.

```Terminal
docker version --format '{{.Client.Version}} / {{.Server.Version}}'
docker buildx version
uname -sr
```

## How to prevent it

- Keep build contexts small with an allowlist ignore file, so less has to be transferred.
- Pin the Docker and buildx versions your CI uses, so a transfer regression is visible as a version change.
- Avoid deeply nested throwaway directories inside a build context where you do not need them.
- When a build error is rare and platform specific, compare environments before rearranging files.

## What the two halves of the transfer agree about

A build context moves in two phases. The sender announces each entry with a stat packet, and the receiver writes the path into a table keyed to a numeric identifier. Later, when the writer on the receiving side actually wants a file's bytes, it asks for that path, the receiver looks it up in the table, sends a request for the identifier, and deletes the entry.

There are two ways to arrive at this error. Ask for a path that is not in the table and you get the form with a path in it. Receive a data packet for an identifier with no pipe open for it and you get the form with a number in it. Both mean the two sides disagree about what has been announced, and neither has anything to do with permissions or with where your path sits relative to the context root.

| Form of the message | What the receiver was doing | What it implies |
| --- | --- | --- |
| `invalid file request <path>` | Looking up a path the writer asked for | The path was never announced, or was already requested once |
| `invalid file request <number>` | Routing an incoming data packet | Data arrived for an identifier with nothing waiting on it |

> Read in the tonistiigi/fsutil receive path vendored into moby/buildkit at commit 99bd9de, on 2026-09-21.

## What it is not, and we checked

The story attached to this message is that a COPY reaching outside the build context produces it. It does not. We built a Dockerfile containing `COPY ../outside.txt /` on this machine and the failure was the ordinary content hash one: the climb is normalized against the context root and you are told that a file of that name is not found there. Nothing mentions a file request, a boundary or an escape.

It is also not a permission problem. An entry the sender cannot read fails on the sending side and is relayed with a different prefix entirely, which is covered on the page linked below. If your message names a permission, you are not on this page's failure.

```Dockerfile
# what a context escape actually produces, captured here
COPY ../outside.txt /
# ERROR: failed to solve: failed to compute cache key: failed to calculate
#        checksum of ref <id>: "/outside.txt": not found
```

## Where it does turn up

The reports we could find cluster around path handling rather than content: nested directories on Windows builds, and cases where the two sides normalize a path differently so the lookup misses a name that was announced in another form. That is consistent with the mechanism, because the table is keyed by the path string the sender sent.

The practical consequence is that this is one of the few build errors where the answer is often a version rather than a change to your files. Establish whether it reproduces on a different Docker version and a different host platform before you start rearranging your context, because the same tree frequently transfers fine elsewhere.

## Why no recorded run backs this page

We could not produce this failure deliberately, and we are not going to publish a run that manufactured one. Getting the two halves of a streaming protocol to disagree on purpose means either patching one of them or finding a platform whose path handling differs, and either way the recorded artifact would be a picture of our own setup rather than evidence about yours.

So the page is built from the two format strings and the code around them, which is where the meaning of the message lives, plus one thing we could check: that the failure people most often attribute to it, a COPY reaching outside the context, produces a completely different message. That negative is the most useful thing on the page and it cost one local build.

## FAQ

### Does invalid file request mean my COPY reached outside the build context?

No. We built exactly that case and got the content hash error instead: the climb is normalized against the context root and the file is reported as not found there. No Docker component prints a message about escaping a context.

### What is the number in invalid file request 41?

It is the internal identifier the transfer assigned to a file when its stat was announced. The numeric form of the message means a data packet arrived for that identifier with nothing waiting to receive it, which is the same bookkeeping disagreement seen from the other side.

### Is this a permissions problem?

No. A file the sender cannot read fails on the sending side and is relayed with a different prefix that names the operation and the system error. This message is produced by the receiver and concerns its own table of announced paths.

### Why does the same repository build fine on another machine?

Because the failure lives in how the two halves of the transfer agree about paths, and that differs between platforms and between versions. It is one of the few build errors where trying a different Docker version is a better first experiment than editing your files.

## References

- [fsutil: the receiver that formats both forms of this message](https://github.com/tonistiigi/fsutil/blob/master/receive.go)
- [moby/buildkit#4741: a path handling report carrying this message](https://github.com/moby/buildkit/issues/4741)
- [Docker docs: the build context and how it is sent](https://docs.docker.com/build/concepts/context/)
- [Docker docs: .dockerignore files](https://docs.docker.com/build/concepts/context/#dockerignore-files)

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
