Error MSB3021 and Team Build

The error message "error MSB3021: Unable to copy file "<filename>" to "<output location>". Access to the path '<output location>' is denied" occurs when the MSBuild Copy task cannot overwrite an existing read-only file. 

Typically in Team Build this error will occur because (a) there seems to be an issue in MSBuild where the same file can get included more than once in the list of files to get copied, and (b) these files will typically be read-only in a Team Build since they are retrieved from version control (and not checked out).  The workarounds for the issue depend on the version of Team Build (and MSBuild) you are using.

Team Build 2005 / MSBuild 2.0

There are two approaches to fixing the issue in Team Build 2005 / MSBuild 2.0 - removing the duplicate entries from the items copied or removing the read-only bit from the files before they are copied. 

For the first possibility, two suggestions for fixing the involved targets (from Microsoft.Common.targets) can be found in an MSBuild forum thread here.  The trick in using these is that you'll need to either (a) modify Microsoft.Common.targets in place, or (b) override the relevant targets in each of your project (e.g. *.csproj) files.  Modifying Microsoft.Common.targets in place is not a great idea, since you'll need to do so on every build machine, your changes will get wiped out on upgrade, etc.  Overriding the targets in each project is annoying as well, since it can potentially require modification of lots of project files.

The second possibility, then, may be a bit easier.  For example, the following target override in your TfsBuild.proj file should work in most cases:

   <Target Name="AfterGet">
    <Exec Command="attrib -r *.* /S" WorkingDirectory="$(SolutionRoot)" />
  </Target>

This logic simply turns off the read-only bit on every file downloaded from version control.  If the only files you copy are *.png files, you can change the file mask for the attrib command to speed things up a bit, etc.  If you are doing an incremental get, you may need to reset the read-only bit at the end of the build or at the beginning of the next build - something like the following should do the trick:

   <Target Name="BeforeGet">
    <Exec Command="attrib +r *.* /S" WorkingDirectory="$(SolutionRoot)" />
  </Target>

Team Build 2008 / MSBuild 3.5

In MSBuild 3.5, an OverwriteReadOnlyFiles property was added that can be set to true to allow Copy tasks involved in the build process to overwrite read-only files in cases like the one outlined here.  As such, a third workaround is possible in Team Build 2008 / MSBuild 3.5.  Note that this workaround will only work for projects that use the 3.5 version of Microsoft.Common.targets - because of the multi-targeting feature available in MSBuild, this will not necessarily be every project built by Team Build 2008.   

To set the OverwriteReadOnlyFiles property to true globally, you can either:

  • Add the text "/p:OverwriteReadOnlyFiles=true" to TfsBuild.rsp for your build definition, or
  • Add the following property group to TfsBuild.proj for your build definition.
   <PropertyGroup>
    <CustomPropertiesForBuild>OverwriteReadOnlyFiles=true</CustomPropertiesForBuild>
  </PropertyGroup>

Comments

  • Anonymous
    October 22, 2007
    PingBack from http://target.wpbloggers.com/?p=3469
  • Anonymous
    October 24, 2007
    Brian Harry on TFS plugin compatibility between TFS 2005 and TFS 2008. Ian Ceicys on NUnit Conversion...
  • Anonymous
    October 18, 2008
    Aaron- I am having a problem when attempting to publish my click once app using your recommendation above.  I'm using TFS08/3.5, and have the following code in my TFSBuild.proj file:   <SolutionToBuild Include="$(BuildProjectFolderPath)/../../Dev/DeskIT/DeskIT.sln">       <Targets></Targets>       <Properties></Properties>   </SolutionToBuild>   <SolutionToPublish Include="$(BuildProjectFolderPath)/../../Dev/DeskIT/DeskIT.sln">     <Targets></Targets>     <Properties>OverwriteReadOnlyFiles=true</Properties>   </SolutionToPublish>I also added the target overload: <Target Name="AfterGet">   <Exec Command="attrib -r . /S" WorkingDirectory="$(SolutionRoot)" /> </Target>Nothing seems to fix the access denied error when MSBuild is attemping to publish my project, this is the error from the buildlog.txt:C:WINDOWSMicrosoft.NETFrameworkv2.0.50727Microsoft.Common.targets(3253,9): error MSB3021: Unable to copy file "D:TeamBuildsDeskITDeskIT DevBinariesDebugDeskITShell.exe.manifest" to "DeskITShell.exe.manifest". Access to the path 'DeskITShell.exe.manifest' is denied.The publish location defined in the project is a network share, and the TFS service account has full control to both the share and the folder.  Any ideas?  Thanks in advance for any help.-Josh
  • Anonymous
    October 22, 2008
    Based on the path in the error message, it looks like your publish location is not being respected and the copy is attempting to place the manifest file into the root directory of your build machine's D: drive.  My guess would be that there is already a read-only copy of the file there which is giving the access denied error.  The real issue would seem to be fixing that path!
  • Anonymous
    May 23, 2011
    Thanks Aaron, it worked for me.I am using Nant for this. <exec program="${MSBuildPath}" verbose="true">   <arg value="${BuildDirNCM}${SolutionFileName}"/>   <arg value="/p:OverwriteReadOnlyFiles=True"/>   <arg value="/p:Configuration=Release"/>   <arg value="/p:Platform=Any CPU"/>   <arg value="/t:Clean,Build"/> </exec>
  • Anonymous
    October 17, 2011
    I am using Team build 2010 and facing the same problem. I even tried"•Add the text "/p:OverwriteReadOnlyFiles=true" to TfsBuild.rsp for your build definition"but it did not work.Is there any other property for TFS build 2010?