Repository: pantsbuild/pants

Issue:
Testing in Docker environment fails with pex FileNotFoundError
**Describe the bug**
When trying to run some tests in my `docker_environment` I get the below error:

```
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/runpy.py", line 187, in _run_module_as_main
    mod_name, mod_spec, code = _get_main_module_details(_Error)
  File "/usr/local/lib/python3.8/runpy.py", line 221, in _get_main_module_details
    return _get_module_details(main_name)
  File "/usr/local/lib/python3.8/runpy.py", line 155, in _get_module_details
    code = loader.get_code(mod_name)
  File "<frozen zipimport>", line 159, in get_code
  File "<frozen zipimport>", line 709, in _get_module_code
  File "<frozen zipimport>", line 536, in _get_data
FileNotFoundError: [Errno 2] No such file or directory: './pex'
```

I have included the full traceback below. If you need any more information please let me know.

**Pants version**
2.16.0.dev5

**OS**
I am developing on a Mac but the tests are supposed to be executed in the `python:3.8-slim` linux Docker container.

**Additional info**
In my root level `BUILD` file I have configured the `docker_environment`
```python
docker_environment(
    name="dev_docker",
    platform="linux_x86_64",
    image="python:3.8-slim",
    python_bootstrap_search_path=["<PATH>"],
)
```

The test `BUILD` file has set the environment

```python
python_tests(
    name="tests", environment="dev_docker"
)
```

<details>
  <summary>pants.toml</summary>

```toml
[GLOBAL]
pants_version = "2.16.0.dev5"
dynamic_ui = true
backend_packages = [
  "pants.backend.build_files.fix.deprecations",
  "pants.backend.build_files.fmt.black",
  "pants.backend.python",
  "pants.backend.python.lint.autoflake",
  "pants.backend.python.lint.black",
  "pants.backend.python.lint.flake8",
  "pants.backend.python.lint.isort",
  "pants.backend.python.lint.pyupgrade",
  "pants.backend.python.typecheck.mypy",
  "pants.backend.docker",
]

[python]
enable_resolves = true
interpreter_constraints = [">=3.8.*"]

[python.resolves_to_only_binary]
__default__= [":all:"]

[python-bootstrap]
search_path = [
  "<PYENV>",
  "<PATH>"
]

[test]
batch_size = 16

[pytest]
args = ["--no-header"]
execution_slot_var = "PANTS_RUNNER_ID"
config = "pyproject.toml"

[docker]
tailor = false

[environments-preview.names]
dev_docker = "//:dev_docker"
```
</details>

<details>
  <summary>full error traceback</summary>

```
pants test src/project:: --print-stacktrace --keep-sandboxes=on_failure
13:23:53.31 [INFO] Completed: Pulling Docker image `python:3.8-slim` because the image is missing locally.
13:23:54.77 [INFO] Preserving local process execution dir /private/var/folders/8b/0w6lmjjx7fsdm_6hhcrjfdfw0000gq/T/pants-sandbox-oEZLFk for Find interpreter for constraints: CPython>=3.8.*
13:23:54.78 [ERROR] 1 Exception encountered:

Engine traceback:
  in select
    ..
  in pants.core.goals.test.run_tests
    `test` goal

Traceback (most recent call last):
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/core/goals/test.py", line 836, in run_tests
    results = await MultiGet(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 360, in MultiGet
    return await _MultiGet(tuple(__arg0))
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 167, in __await__
    result = yield self.gets
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 475, in run_python_tests
    setup = await Get(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 475, in run_python_tests
    setup = await Get(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 262, in setup_pytest_for_target
    ) = await MultiGet(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 451, in MultiGet
    return await _MultiGet((__arg0, __arg1, __arg2, __arg3, __arg4, __arg5))
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 167, in __await__
    result = yield self.gets
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 475, in run_python_tests
    setup = await Get(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 262, in setup_pytest_for_target
    ) = await MultiGet(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 451, in MultiGet
    return await _MultiGet((__arg0, __arg1, __arg2, __arg3, __arg4, __arg5))
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 167, in __await__
    result = yield self.gets
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 262, in setup_pytest_for_target
    ) = await MultiGet(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 451, in MultiGet
    return await _MultiGet((__arg0, __arg1, __arg2, __arg3, __arg4, __arg5))
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 167, in __await__
    result = yield self.gets
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 475, in run_python_tests
    setup = await Get(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 262, in setup_pytest_for_target
    ) = await MultiGet(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 451, in MultiGet
    return await _MultiGet((__arg0, __arg1, __arg2, __arg3, __arg4, __arg5))
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 167, in __await__
    result = yield self.gets
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 657, in create_pex
    result = await Get(BuildPexResult, PexRequest, request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/goals/pytest_runner.py", line 262, in setup_pytest_for_target
    ) = await MultiGet(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 451, in MultiGet
    return await _MultiGet((__arg0, __arg1, __arg2, __arg3, __arg4, __arg5))
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 167, in __await__
    result = yield self.gets
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 657, in create_pex
    result = await Get(BuildPexResult, PexRequest, request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 657, in create_pex
    result = await Get(BuildPexResult, PexRequest, request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 657, in create_pex
    result = await Get(BuildPexResult, PexRequest, request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 657, in create_pex
    result = await Get(BuildPexResult, PexRequest, request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 657, in create_pex
    result = await Get(BuildPexResult, PexRequest, request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 531, in build_pex
    pex_python_setup = await _determine_pex_python_and_platforms(request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 401, in _determine_pex_python_and_platforms
    python = await Get(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 531, in build_pex
    pex_python_setup = await _determine_pex_python_and_platforms(request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 401, in _determine_pex_python_and_platforms
    python = await Get(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 531, in build_pex
    pex_python_setup = await _determine_pex_python_and_platforms(request)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 401, in _determine_pex_python_and_platforms
    python = await Get(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 626, in native_engine_generator_send
    res = rule.send(arg) if err is None else rule.throw(throw or err)
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/backend/python/util_rules/pex.py", line 312, in find_interpreter
    result = await Get(
  File "/Users/me/Library/Caches/nce/a7a7e5c8d0659936773c836830336c0e3743f47588d74ecdce11e40b499a7003/bindings/venvs/2.16.0.dev5/lib/python3.9/site-packages/pants/engine/internals/selectors.py", line 120, in __await__
    result = yield self
pants.engine.process.ProcessExecutionFailure: Process 'Find interpreter for constraints: CPython>=3.8.*' failed with exit code 1.
stdout:

stderr:
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/runpy.py", line 187, in _run_module_as_main
    mod_name, mod_spec, code = _get_main_module_details(_Error)
  File "/usr/local/lib/python3.8/runpy.py", line 221, in _get_main_module_details
    return _get_module_details(main_name)
  File "/usr/local/lib/python3.8/runpy.py", line 155, in _get_module_details
    code = loader.get_code(mod_name)
  File "<frozen zipimport>", line 159, in get_code
  File "<frozen zipimport>", line 709, in _get_module_code
  File "<frozen zipimport>", line 536, in _get_data
FileNotFoundError: [Errno 2] No such file or directory: './pex'

```
</details>

<details>
  <summary>__run.sh</summary>

```
#!/bin/bash
# This command line should execute the same process as pants did internally.
export CPPFLAGS= LANG=C.UTF-8 LDFLAGS= PATH=$'/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin' PEX_IGNORE_RCFILES=true PEX_PYTHON_PATH=$'/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' PEX_ROOT=.cache/pex_root
cd /private/var/folders/8b/0w6lmjjx7fsdm_6hhcrjfdfw0000gq/T/pants-sandbox-2F5JHo
/usr/local/bin/python ./pex --tmpdir .tmp --pip-version 20.3.4-patched --python-path $'/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' --interpreter-constraint $'CPython>=3.8.*' -- -c $'import hashlib, os, sys\n\npython = os.path.realpath(sys.executable)\nprint(python)\n\nhasher = hashlib.sha256()\nwith open(python, "rb") as fp:\n  for chunk in iter(lambda: fp.read(8192), b""):\n      hasher.update(chunk)\nprint(hasher.hexdigest())\n'
```
</details>


Discussion:
Unfortunately, this looks like a race condition: I was able to reproduce it twice on macOS in different docker images, but not reliably.

My best guess is that this has to do with Docker-for-Mac's filesystem sharing being inconsistent. That is very much a moving target though: they changed implementations from `osxfs` to `gRPC FUSE` at some point, and the documentation seems to straddle both worlds with regard to explaining what the default filesystem consistency level is.

I'll be working on this issue with high priority.
Hm. So after studying the various `osxfs` and `gRPC FUSE` issues in https://github.com/docker/for-mac/ , and then skimming through most of https://github.com/docker/roadmap/issues/7, I still don't have an answer as to what the default filesystem consistency level is with `gRPC FUSE` ... and the code is closed source. Even a core developer is unclear on this point: https://github.com/docker/roadmap/issues/7#issuecomment-678407160

Having said that: in order to observe the latest settings in Docker for macOS, I upgraded to version 4.16.2. And since doing so, I have not been able to reproduce this issue (still using `gRPC FUSE`, rather than the even newer `VirtioFS` filesystem implementation).

----

Although I do see some potential paths forward for removing the need to bind-mount process inputs (tar-piping them into the container is one), the performance and correctness of bind mounts on macOS is a very rapidly changing topic, so I think that for now my recommendation would be to see whether you are able to reproduce this issue after updating Docker for macOS.
Mm: correction: the consistency levels which were relevant to `osxfs` are definitely not relevant to `gRPC FUSE`: https://github.com/docker/for-mac/issues/5402 ... which I think leaves a Docker for macOS upgrade as the clear path right now.
Thank you for looking into this. I can confirm that after upgrading to version 4.16.2 I no longer see the error.
Ok, thanks. Not conclusive, but a pretty clear sign.
We've had another report of this issue, even while running Docker `4.16.2`.

Resolving patch:
diff --git a/src/python/pants/engine/internals/scheduler.py b/src/python/pants/engine/internals/scheduler.py
--- a/src/python/pants/engine/internals/scheduler.py
+++ b/src/python/pants/engine/internals/scheduler.py
@@ -209,6 +209,7 @@ def __init__(
             local_parallelism=execution_options.process_execution_local_parallelism,
             local_enable_nailgun=execution_options.process_execution_local_enable_nailgun,
             remote_parallelism=execution_options.process_execution_remote_parallelism,
+            docker_strategy=execution_options.docker_strategy.value,
             child_max_memory=execution_options.process_total_child_memory_usage or 0,
             child_default_memory=execution_options.process_per_child_memory_usage,
             graceful_shutdown_timeout=execution_options.process_execution_graceful_shutdown_timeout,
diff --git a/src/python/pants/init/engine_initializer.py b/src/python/pants/init/engine_initializer.py
--- a/src/python/pants/init/engine_initializer.py
+++ b/src/python/pants/init/engine_initializer.py
@@ -42,7 +42,6 @@
 from pants.init import specs_calculator
 from pants.init.bootstrap_scheduler import BootstrapStatus
 from pants.option.global_options import (
-    DEFAULT_EXECUTION_OPTIONS,
     DynamicRemoteOptions,
     ExecutionOptions,
     GlobalOptions,
@@ -237,8 +236,6 @@ def setup_graph_extended(
         union_membership: UnionMembership
         registered_target_types = RegisteredTargetTypes.create(build_configuration.target_types)
 
-        execution_options = execution_options or DEFAULT_EXECUTION_OPTIONS
-
         @rule
         def parser_singleton() -> Parser:
             return Parser(
diff --git a/src/python/pants/option/global_options.py b/src/python/pants/option/global_options.py
--- a/src/python/pants/option/global_options.py
+++ b/src/python/pants/option/global_options.py
@@ -27,6 +27,7 @@
 from pants.engine.env_vars import CompleteEnvironmentVars
 from pants.engine.fs import FileContent
 from pants.engine.internals.native_engine import PyExecutor
+from pants.engine.platform import Platform
 from pants.option.custom_types import memory_size
 from pants.option.errors import OptionsError
 from pants.option.option_types import (
@@ -130,6 +131,14 @@ class KeepSandboxes(Enum):
     never = "never"
 
 
+class DockerStrategy(Enum):
+    """An enum for the global option `docker_strategy`."""
+
+    auto = "auto"
+    mount = "mount"
+    pipe = "pipe"
+
+
 @enum.unique
 class AuthPluginState(Enum):
     OK = "ok"
@@ -491,6 +500,8 @@ class ExecutionOptions:
     process_execution_graceful_shutdown_timeout: int
     cache_content_behavior: CacheContentBehavior
 
+    docker_strategy: DockerStrategy
+
     process_total_child_memory_usage: int | None
     process_per_child_memory_usage: int
 
@@ -535,6 +546,7 @@ def from_options(
             process_execution_cache_namespace=bootstrap_options.process_execution_cache_namespace,
             process_execution_graceful_shutdown_timeout=bootstrap_options.process_execution_graceful_shutdown_timeout,
             process_execution_local_enable_nailgun=bootstrap_options.process_execution_local_enable_nailgun,
+            docker_strategy=GlobalOptions.resolve_docker_strategy(bootstrap_options),
             cache_content_behavior=bootstrap_options.cache_content_behavior,
             process_total_child_memory_usage=bootstrap_options.process_total_child_memory_usage,
             process_per_child_memory_usage=bootstrap_options.process_per_child_memory_usage,
@@ -620,6 +632,7 @@ def from_options(cls, options: OptionValueContainer) -> LocalStoreOptions:
     keep_sandboxes=KeepSandboxes.never,
     local_cache=True,
     cache_content_behavior=CacheContentBehavior.fetch,
+    docker_strategy=DockerStrategy.auto,
     process_execution_local_enable_nailgun=True,
     process_execution_graceful_shutdown_timeout=3,
     # Remote store setup.
@@ -1042,7 +1055,11 @@ class BootstrapOptions:
         help=softwrap(
             """
             The maximum number of threads to use to execute `@rule` logic. Defaults to
-            a small multiple of `--rule-threads-core`.
+            `16 * --rule-threads-core`.
+
+            Note that setting too low a `--rule-threads-max` value can lead to deadlocks: Pants
+            uses blocking operations internally for a few use cases, and if the pool of blocking
+            threads is exhausted, those use cases will wait.
             """
         ),
     )
@@ -1185,6 +1202,24 @@ class BootstrapOptions:
             """
         ),
     )
+    process_execution_docker_strategy = EnumOption(
+        default=DEFAULT_EXECUTION_OPTIONS.docker_strategy,
+        help=softwrap(
+            """
+            The strategy used to provide inputs to Docker containers when the `docker_environment`
+            target is in use.
+
+            The `mount` strategy provides inputs via bind mounts. The `pipe` strategy provides
+            inputs by tar-pipe'ing them into the container.
+
+            The default value of `auto` will choose the fastest known-consistent strategy for the
+            platform that Pants is running on, which generally means using the `pipe` strategy when
+            Docker is implemented via virtualization (on macOS and Windows in particular). See
+            https://github.com/docker/roadmap/issues/7 for more information on macOS filesystem
+            virtualization status.
+            """
+        ),
+    )
     cache_content_behavior = EnumOption(
         advanced=True,
         default=DEFAULT_EXECUTION_OPTIONS.cache_content_behavior,
@@ -1823,10 +1858,22 @@ def validate_remote_headers(opt_name: str) -> None:
 
     @staticmethod
     def create_py_executor(bootstrap_options: OptionValueContainer) -> PyExecutor:
+        # NB: See the `--rule-threads-max` option help for a warning on setting this too low.
+        #
+        # This value is chosen somewhat arbitrarily, but has a few concerns at play:
+        # * When set too low, tasks using `Executor::spawn_blocking` on the Rust side can deadlock
+        #   when too many blocking operations already running.
+        # * Higher thread counts mean less bounded access to the LMDB store (which is the primary user
+        #   of blocking tasks), which is good up to a point, but then begins to increase kernel time
+        #   as many threads are blocked waiting for IO and locks.
+        #
+        # The value 16 was chosen to avoid deadlocks with all current `spawn_blocking` calls, and based
+        # on the observation that performance drops off by 2-3% points (on my machine!) when multiples
+        # of 32 and 64.
         rule_threads_max = (
             bootstrap_options.rule_threads_max
             if bootstrap_options.rule_threads_max
-            else 4 * bootstrap_options.rule_threads_core
+            else 16 * bootstrap_options.rule_threads_core
         )
         return PyExecutor(
             core_threads=bootstrap_options.rule_threads_core, max_threads=rule_threads_max
@@ -1853,6 +1900,19 @@ def resolve_keep_sandboxes(
         else:
             raise TypeError(f"Unexpected option value for `keep_sandboxes`: {resolved_value}")
 
+    @staticmethod
+    def resolve_docker_strategy(
+        bootstrap_options: OptionValueContainer,
+    ) -> DockerStrategy:
+        strategy = cast(DockerStrategy, bootstrap_options.process_execution_docker_strategy)
+        if strategy == DockerStrategy.auto:
+            return (
+                DockerStrategy.pipe
+                if Platform.create_for_localhost().is_macos
+                else DockerStrategy.mount
+            )
+        return strategy
+
     @staticmethod
     def compute_pants_ignore(buildroot, global_options):
         """Computes the merged value of the `--pants-ignore` flag.


Test patch:
diff --git a/src/python/pants/engine/internals/scheduler_test_base.py b/src/python/pants/engine/internals/scheduler_test_base.py
--- a/src/python/pants/engine/internals/scheduler_test_base.py
+++ b/src/python/pants/engine/internals/scheduler_test_base.py
@@ -2,12 +2,17 @@
 # Licensed under the Apache License, Version 2.0 (see LICENSE).
 
 import os
+from dataclasses import replace
 from pathlib import Path
 
 from pants.engine.internals.native_engine import PyExecutor
 from pants.engine.internals.scheduler import Scheduler, SchedulerSession
 from pants.engine.unions import UnionMembership
-from pants.option.global_options import DEFAULT_EXECUTION_OPTIONS, DEFAULT_LOCAL_STORE_OPTIONS
+from pants.option.global_options import (
+    DEFAULT_EXECUTION_OPTIONS,
+    DEFAULT_LOCAL_STORE_OPTIONS,
+    DockerStrategy,
+)
 from pants.util.contextutil import temporary_file_path
 from pants.util.dirutil import safe_mkdtemp
 from pants.util.logging import LogLevel
@@ -35,6 +40,7 @@ def mk_scheduler(
 
         local_execution_root_dir = os.path.realpath(safe_mkdtemp())
         named_caches_dir = os.path.realpath(safe_mkdtemp())
+        execution_options = replace(DEFAULT_EXECUTION_OPTIONS, docker_strategy=DockerStrategy.mount)
         scheduler = Scheduler(
             ignore_patterns=[],
             use_gitignore=False,
@@ -45,7 +51,7 @@ def mk_scheduler(
             rules=rules,
             union_membership=UnionMembership({}),
             executor=self._executor,
-            execution_options=DEFAULT_EXECUTION_OPTIONS,
+            execution_options=execution_options,
             local_store_options=DEFAULT_LOCAL_STORE_OPTIONS,
             include_trace_on_error=include_trace_on_error,
         )
diff --git a/src/python/pants/engine/rules_test.py b/src/python/pants/engine/rules_test.py
--- a/src/python/pants/engine/rules_test.py
+++ b/src/python/pants/engine/rules_test.py
@@ -2,7 +2,7 @@
 # Licensed under the Apache License, Version 2.0 (see LICENSE).
 
 import re
-from dataclasses import dataclass
+from dataclasses import dataclass, replace
 from enum import Enum
 from pathlib import Path
 from textwrap import dedent
@@ -28,7 +28,11 @@
     rule_helper,
 )
 from pants.engine.unions import UnionMembership
-from pants.option.global_options import DEFAULT_EXECUTION_OPTIONS, DEFAULT_LOCAL_STORE_OPTIONS
+from pants.option.global_options import (
+    DEFAULT_EXECUTION_OPTIONS,
+    DEFAULT_LOCAL_STORE_OPTIONS,
+    DockerStrategy,
+)
 from pants.testutil.rule_runner import MockGet, run_rule_with_mocks
 from pants.util.enums import match
 from pants.util.logging import LogLevel
@@ -36,6 +40,7 @@
 
 def create_scheduler(rules, validate=True):
     """Create a Scheduler."""
+    execution_options = replace(DEFAULT_EXECUTION_OPTIONS, docker_strategy=DockerStrategy.mount)
     return Scheduler(
         ignore_patterns=[],
         use_gitignore=False,
@@ -46,7 +51,7 @@ def create_scheduler(rules, validate=True):
         rules=rules,
         union_membership=UnionMembership({}),
         executor=PyExecutor(core_threads=2, max_threads=4),
-        execution_options=DEFAULT_EXECUTION_OPTIONS,
+        execution_options=execution_options,
         local_store_options=DEFAULT_LOCAL_STORE_OPTIONS,
         validate_reachability=validate,
     )
diff --git a/src/rust/engine/fs/store/src/snapshot_tests.rs b/src/rust/engine/fs/store/src/snapshot_tests.rs
--- a/src/rust/engine/fs/store/src/snapshot_tests.rs
+++ b/src/rust/engine/fs/store/src/snapshot_tests.rs
@@ -174,6 +174,46 @@ async fn snapshot_recursive_directories_including_empty() {
   );
 }
 
+#[tokio::test]
+async fn snapshot_tar_roundtrip() {
+  let (store, dir, posix_fs, digester) = setup();
+
+  let cats = PathBuf::from("cats");
+  let roland = cats.join("roland");
+  std::fs::create_dir_all(dir.path().join(cats)).unwrap();
+  make_file(&dir.path().join(&roland), STR.as_bytes(), 0o600);
+
+  let path_stats = expand_all_sorted(posix_fs).await;
+  let original_snapshot = Snapshot::from_path_stats(digester, path_stats)
+    .await
+    .unwrap();
+
+  // Materialize the Snapshot via tar, and confirm that capturing it results in the same digest.
+  let (_, dir, posix_fs, digester) = setup();
+  let mut tar = std::process::Command::new("tar")
+    .args(["-xf", "-"])
+    .stdin(std::process::Stdio::piped())
+    .current_dir(&dir)
+    .spawn()
+    .unwrap();
+  store
+    .directory_as_tar_file(
+      original_snapshot.tree.clone().into(),
+      tar.stdin.take().unwrap(),
+    )
+    .await
+    .unwrap();
+
+  assert_eq!(0, tar.wait().unwrap().code().unwrap());
+
+  let path_stats = expand_all_sorted(posix_fs).await;
+  let snapshot = Snapshot::from_path_stats(digester, path_stats)
+    .await
+    .unwrap();
+
+  assert_eq!(original_snapshot.digest, snapshot.digest);
+}
+
 #[tokio::test]
 async fn merge_directories_two_files() {
   let (store, _, _, _) = setup();
diff --git a/src/rust/engine/process_execution/src/cache_tests.rs b/src/rust/engine/process_execution/src/cache_tests.rs
--- a/src/rust/engine/process_execution/src/cache_tests.rs
+++ b/src/rust/engine/process_execution/src/cache_tests.rs
@@ -32,7 +32,7 @@ fn create_local_runner() -> (Box<dyn CommandRunnerTrait>, Store, TempDir) {
     store.clone(),
     runtime,
     base_dir.path().to_owned(),
-    NamedCaches::new(named_cache_dir),
+    NamedCaches::new(named_cache_dir).unwrap(),
     ImmutableInputs::new(store.clone(), base_dir.path()).unwrap(),
     KeepSandboxes::Never,
   ));
diff --git a/src/rust/engine/process_execution/src/docker_tests.rs b/src/rust/engine/process_execution/src/docker_tests.rs
--- a/src/rust/engine/process_execution/src/docker_tests.rs
+++ b/src/rust/engine/process_execution/src/docker_tests.rs
@@ -16,8 +16,9 @@ use testutil::data::{TestData, TestDirectory};
 use testutil::{owned_string_vec, relative_paths};
 use workunit_store::{RunningWorkunit, WorkunitStore};
 
-use super::docker::SANDBOX_BASE_PATH_IN_CONTAINER;
-use crate::docker::{DockerOnceCell, ImagePullCache};
+use crate::docker::{
+  DockerOnceCell, DockerStrategy, ImagePullCache, SANDBOX_BASE_PATH_IN_CONTAINER,
+};
 use crate::local::KeepSandboxes;
 use crate::local_tests::named_caches_and_immutable_inputs;
 use crate::{
@@ -102,9 +103,7 @@ async fn runner_errors_if_docker_image_not_set() {
     .await
     .unwrap_err();
   if let ProcessError::Unclassified(msg) = &err {
-    assert!(
-      msg.contains("The Docker execution strategy was not set on the Process, but the Docker CommandRunner was used")
-    );
+    assert!(msg.ends_with(", but the Docker CommandRunner was used."));
   } else {
     panic!("unexpected value: {err:?}")
   }
@@ -174,7 +173,7 @@ fn extract_env(
   exclude_keys: &[&str],
 ) -> Result<BTreeMap<String, String>, String> {
   let content =
-    String::from_utf8(content).map_err(|_| "Invalid UTF-8 in env output".to_string())?;
+    String::from_utf8(content).map_err(|e| format!("Invalid UTF-8 in env output: {e}"))?;
   let result = content
     .split('\n')
     .filter(|line| !line.is_empty())
@@ -190,6 +189,18 @@ fn extract_env(
   Ok(result)
 }
 
+fn extract_ls(content: Vec<u8>) -> Result<Vec<String>, String> {
+  let content =
+    String::from_utf8(content).map_err(|e| format!("Invalid UTF-8 in ls output: {e}"))?;
+  let mut items: Vec<_> = content
+    .split('\n')
+    .filter(|line| !line.is_empty())
+    .map(|line| line.to_owned())
+    .collect();
+  items.sort();
+  Ok(items)
+}
+
 #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
 #[cfg(unix)]
 async fn env() {
@@ -442,6 +453,8 @@ async fn output_overlapping_file_and_dir() {
 async fn append_only_cache_created() {
   skip_if_no_docker_available_in_macos_ci!();
 
+  let _logger = env_logger::try_init();
+
   let name = "geo";
   let dest_base = ".cache";
   let cache_name = CacheName::new(name.to_owned()).unwrap();
@@ -495,6 +508,7 @@ async fn test_chroot_placeholder() {
       .docker(IMAGE.to_owned()),
     work_root.clone(),
     KeepSandboxes::Always,
+    DockerStrategy::Mount,
     &mut workunit,
     None,
     None,
@@ -508,6 +522,53 @@ async fn test_chroot_placeholder() {
   assert!(got_env.get(&"PATH".to_string()).unwrap().ends_with("/bin"));
 }
 
+#[tokio::test(flavor = "multi_thread")]
+async fn test_piped_inputs() {
+  skip_if_no_docker_available_in_macos_ci!();
+
+  let (_, mut workunit) = WorkunitStore::setup_for_tests();
+
+  let store_dir = TempDir::new().unwrap();
+  let executor = task_executor::Executor::new();
+  let store = Store::local_only(executor.clone(), store_dir.path()).unwrap();
+
+  store
+    .store_file_bytes(TestData::roland().bytes(), false)
+    .await
+    .expect("Error saving file bytes");
+  store
+    .record_directory(&TestDirectory::containing_roland().directory(), true)
+    .await
+    .expect("Error saving directory");
+
+  let work_tmpdir = TempDir::new().unwrap();
+
+  let mut process = Process::new(vec!["/bin/ls".to_owned()]).docker(IMAGE.to_owned());
+  process.input_digests = InputDigests::new(
+    &store,
+    TestDirectory::containing_roland().directory_digest(),
+    BTreeMap::default(),
+    BTreeSet::default(),
+  )
+  .await
+  .unwrap();
+
+  let result = run_command_via_docker_in_dir(
+    process,
+    work_tmpdir.path().to_owned(),
+    KeepSandboxes::Always,
+    DockerStrategy::Pipe,
+    &mut workunit,
+    Some(store),
+    Some(executor),
+  )
+  .await
+  .unwrap();
+
+  let got_ls = extract_ls(result.stdout_bytes).unwrap();
+  assert_eq!(vec!["roland.ext"], got_ls);
+}
+
 #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
 async fn all_containing_directories_for_outputs_are_created() {
   skip_if_no_docker_available_in_macos_ci!();
@@ -578,7 +639,7 @@ async fn timeout() {
   ];
 
   let mut process = Process::new(argv).docker(IMAGE.to_owned());
-  process.timeout = Some(Duration::from_millis(500));
+  process.timeout = Some(Duration::from_secs(2));
   process.description = "sleepy-cat".to_string();
 
   let result = run_command_via_docker(process).await.unwrap();
@@ -634,6 +695,7 @@ async fn working_directory() {
     process,
     work_dir.path().to_owned(),
     KeepSandboxes::Never,
+    DockerStrategy::Mount,
     &mut workunit,
     Some(store),
     Some(executor),
@@ -703,6 +765,7 @@ async fn immutable_inputs() {
     process,
     work_dir.path().to_owned(),
     KeepSandboxes::Never,
+    DockerStrategy::Mount,
     &mut workunit,
     Some(store),
     Some(executor),
@@ -723,6 +786,7 @@ async fn run_command_via_docker_in_dir(
   mut req: Process,
   dir: PathBuf,
   cleanup: KeepSandboxes,
+  strategy: DockerStrategy,
   workunit: &mut RunningWorkunit,
   store: Option<Store>,
   executor: Option<task_executor::Executor>,
@@ -746,6 +810,7 @@ async fn run_command_via_docker_in_dir(
     named_caches,
     immutable_inputs,
     cleanup,
+    strategy,
   )?;
   let result: Result<_, ProcessError> = async {
     let original = runner.run(Context::default(), workunit, req).await?;
@@ -775,6 +840,7 @@ async fn run_command_via_docker(req: Process) -> Result<LocalTestResult, Process
     req,
     work_dir_path,
     KeepSandboxes::Never,
+    DockerStrategy::Mount,
     &mut workunit,
     None,
     None,
diff --git a/src/rust/engine/process_execution/src/local_tests.rs b/src/rust/engine/process_execution/src/local_tests.rs
--- a/src/rust/engine/process_execution/src/local_tests.rs
+++ b/src/rust/engine/process_execution/src/local_tests.rs
@@ -747,8 +747,7 @@ async fn prepare_workdir_exclusive_relative() {
     work_dir.path().to_owned(),
     &process,
     TestDirectory::recursive().directory_digest(),
-    store,
-    executor,
+    &store,
     &named_caches,
     &immutable_inputs,
     None,
@@ -769,7 +768,7 @@ pub(crate) fn named_caches_and_immutable_inputs(
 
   (
     root,
-    NamedCaches::new(named_cache_dir),
+    NamedCaches::new(named_cache_dir).unwrap(),
     ImmutableInputs::new(store, &root_path).unwrap(),
   )
 }
diff --git a/src/rust/engine/process_execution/src/nailgun/tests.rs b/src/rust/engine/process_execution/src/nailgun/tests.rs
--- a/src/rust/engine/process_execution/src/nailgun/tests.rs
+++ b/src/rust/engine/process_execution/src/nailgun/tests.rs
@@ -22,7 +22,7 @@ fn pool(size: usize) -> (NailgunPool, NamedCaches, ImmutableInputs) {
   let pool = NailgunPool::new(base_dir.clone(), size, store.clone(), executor);
   (
     pool,
-    NamedCaches::new(named_caches_dir.path().to_owned()),
+    NamedCaches::new(named_caches_dir.path().to_owned()).unwrap(),
     ImmutableInputs::new(store, &base_dir).unwrap(),
   )
 }