Skip to content
Latchkey

MSBuild "MSB3027: could not copy ... file is locked" in CI

MSB3027 means MSBuild tried to copy an output file but the destination (or source) was held open by another process and the copy exhausted its retries. On a busy runner this is usually a transient lock from a lingering test host, antivirus scan, or a parallel build touching the same file.

What this error means

The build fails with MSB3027 naming the file and the process holding the lock, after several copy retries. It is often intermittent across runs.

dotnet
error MSB3027: Could not copy "obj/App.dll" to "bin/App.dll". Exceeded retry count of 10.
Failed. The file is locked by: "testhost (12345)"

Diagnose it: SDK version and restore first

Most .NET CI failures are an SDK mismatch or a restore that did not happen. global.json pins the SDK, and if the runner does not have that exact version the failure message is about the project rather than the SDK.

Terminal
dotnet --info
cat global.json 2>/dev/null

# restore explicitly so a restore failure is not reported as a build failure
dotnet restore --verbosity normal
dotnet build --no-restore -warnaserror

Common causes

A lingering process holds the output file

A previous test host, a still-running app instance, or a parallel build target keeps the DLL/EXE open, so the copy cannot replace it.

On-runner scanning or indexing locks the file

Antivirus or file indexing on the runner briefly locks freshly written outputs, intermittently failing the copy.

How to fix it

Kill lingering processes and serialize the copy

  1. Ensure prior test/app processes are terminated before the build step.
  2. Avoid two jobs writing the same output directory concurrently.
  3. Re-run the job; the lock is usually gone on a fresh attempt.

Lean on auto-retry for transient locks

  1. Treat a single MSB3027 with no code change as transient and re-run.
  2. On self-healing managed runners (Latchkey), transient file-lock copy failures are retried automatically so a one-off lock does not fail the pipeline.

How to prevent it

  • Do not run multiple jobs against the same output path on one runner.
  • Stop background app/test processes before rebuilding.
  • Run CI on self-healing managed runners that auto-retry transient file-lock failures.

Frequently asked questions

What causes MSBuild "MSB3027: could not copy ... file is locked" in CI?
There are 2 common causes: a lingering process holds the output file and on-runner scanning or indexing locks the file. A previous test host, a still-running app instance, or a parallel build target keeps the DLL/EXE open, so the copy cannot replace it.
How do I fix MSBuild "MSB3027: could not copy ... file is locked" in CI?
There are 2 fixes depending on which cause you have: kill lingering processes and serialize the copy and lean on auto-retry for transient locks. Work through them in order, since the first is the most common.
What does MSBuild "MSB3027: could not copy ... file is locked" in CI actually mean?
The build fails with MSB3027 naming the file and the process holding the lock, after several copy retries.
How do I stop MSBuild "MSB3027: could not copy ... file is locked" in CI happening again?
Do not run multiple jobs against the same output path on one runner. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card