Skip to content

Copy task should retry on FileNotFoundException (MSB3030) during parallel builds #13599

@wtgodbe

Description

@wtgodbe

Problem

The Copy task checks File.Exists on source files before its retry loop. When the source doesn't exist, it immediately logs MSB3030 and returns false — no retry. The Retries/CopyRetryCount parameter only applies to IOException during the actual File.Copy call.

// src/Tasks/Copy.cs — outside the retry loop
{
    Log.LogErrorWithCodeFromResources("Copy.SourceFileNotFound", ...);
    return false;  // MSB3030 — no retry
}

This causes flaky build failures in large parallel builds (/m) where shared dependency projects are rebuilt by multiple consumer projects. When a dependency's CopyFilesToOutputDirectory overwrites a DLL/PDB, consumer projects running _CopyFilesMarkedCopyLocal can see the source file as transiently missing.

Impact

In dotnet/aspnetcore, this is tracked as Known Build Error #62807 with ~25 hits per month. The only current mitigation is full build retry via Build Analysis, which wastes 30+ minutes per occurrence.

Reproduction

Any large parallel MSBuild solution where:

  1. Project A is a shared dependency (referenced by 100+ projects)
  2. Build runs with /m (unlimited parallelism)
  3. Project A's CopyFilesToOutputDirectory runs on one MSBuild node
  4. A consumer's _CopyFilesMarkedCopyLocal runs on another node simultaneously
  5. The source file in bin/ is briefly unavailable during the overwrite

Proposed Fix

Extend the retry loop in the Copy task to cover FileNotFoundException (or specifically the File.Exists pre-check), similar to how IOException is already retried during the copy operation. This would allow the Retries and RetryDelayMilliseconds parameters to protect against transiently-missing source files.

Workaround

We've added a BeforeTargets="_CopyFilesMarkedCopyLocal" gate in aspnetcore that waits for missing source files before the Copy task runs. This reduces the race window but doesn't eliminate the TOCTOU gap entirely.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: TasksIssues impacting the tasks shipped in Microsoft.Build.Tasks.Core.dll.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions