Msbuild: Internal MSBuild Error: could not load type Microsoft.Build.Utilities.ToolLocationHelper

Created on 7 Sep 2016  路  10Comments  路  Source: dotnet/msbuild

Encountering an error trying to parse a simple csproj using Microsoft.Build APIs

Microsoft.Build.Shared.InternalErrorException: MSB0001: Internal MSBuild Error: Type information for Microsoft.Build.Utilities.ToolLocationHelper was present in the whitelist cache as Microsoft.Build.Utilities.ToolLocationHelper, Microsoft.Build.Utilities.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a but the type could not be loaded.

Repro
dotnet cli 1.0.0-preview3-003585
Microsoft.Build 0.1.0-preview-00033-160829
Microsoft.Build.Framework 0.1.0-preview-00033-160829

Project

<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="**\*.cs" Exclude="$(GlobalExclude)" />
    <EmbeddedResource Include="**\*.resx" Exclude="$(GlobalExclude)" />
    <None Include="project.json" />
  </ItemGroup>

  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

My code:

``` c#
var msBuildFile = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? "MSBuild.exe"
: "MSBuild";

        // workaround https://github.com/Microsoft/msbuild/issues/999
        Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", Path.Combine(dotNetCoreSdkPath, msBuildFile));

        var globalProperties = new Dictionary<string, string>
        {
            { "DesignTimeBuild", "true" },
            { "Configuration", "Debug" },
            { "MSBuildExtensionsPath",  dotNetCoreSdkPath },
        };

        var xmlReader = XmlReader.Create(csProjFileInfo.CreateReadStream());
        var projectCollection = new ProjectCollection();
        return new Project(xmlReader, globalProperties, /*toolsVersion: */ null, projectCollection);
Stack trace:
<details>

Microsoft.Build.Shared.InternalErrorException: MSB0001: Internal MSBuild Error: Type information for Microsoft.Build.Utilities.ToolLocationHelper was present in the whitelist cache as Microsoft.Build.Utilities.ToolLocationHelper, Microsoft.Build.Utilities.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a but the type could not be loaded. unexpectedly null
at Microsoft.Build.Shared.ErrorUtilities.ThrowInternalError(String message, Object[] args)
at Microsoft.Build.Evaluation.Expander2.Function1.GetTypeForStaticMethod(String typeName, String simpleMethodName)
at Microsoft.Build.Evaluation.Expander2.Function1.ExtractPropertyFunction(String expressionFunction, IElementLocation elementLocation, Object propertyValue, UsedUninitializedProperties usedUnInitializedProperties)
at Microsoft.Build.Evaluation.Expander2.PropertyExpander1.ExpandPropertyBody(String propertyBody, Object propertyValue, IPropertyProvider1 properties, ExpanderOptions options, IElementLocation elementLocation, UsedUninitializedProperties usedUninitializedProperties) at Microsoft.Build.Evaluation.Expander2.PropertyExpander1.ExpandPropertiesLeaveTypedAndEscaped(String expression, IPropertyProvider1 properties, ExpanderOptions options, IElementLocation elementLocation, UsedUninitializedProperties usedUninitializedProperties)
at Microsoft.Build.Evaluation.Expander2.PropertyExpander1.ExpandPropertiesLeaveEscaped(String expression, IPropertyProvider1 properties, ExpanderOptions options, IElementLocation elementLocation, UsedUninitializedProperties usedUninitializedProperties) at Microsoft.Build.Evaluation.Expander2.ExpandIntoStringLeaveEscaped(String expression, ExpanderOptions options, IElementLocation elementLocation)
at Microsoft.Build.Evaluation.Evaluator4.EvaluatePropertyElement(ProjectPropertyElement propertyElement) at Microsoft.Build.Evaluation.Evaluator4.EvaluatePropertyGroupElement(ProjectPropertyGroupElement propertyGroupElement)
at Microsoft.Build.Evaluation.Evaluator4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) at Microsoft.Build.Evaluation.Evaluator4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)
at Microsoft.Build.Evaluation.Evaluator4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) at Microsoft.Build.Evaluation.Evaluator4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)
at Microsoft.Build.Evaluation.Evaluator4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) at Microsoft.Build.Evaluation.Evaluator4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)
at Microsoft.Build.Evaluation.Evaluator4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) at Microsoft.Build.Evaluation.Evaluator4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)
at Microsoft.Build.Evaluation.Evaluator4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport) at Microsoft.Build.Evaluation.Evaluator4.Evaluate()
at Microsoft.Build.Evaluation.Project.ReevaluateIfNecessary(ILoggingService loggingServiceForEvaluation)
at Microsoft.Build.Evaluation.Project.Initialize(IDictionary2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectLoadSettings loadSettings) at Microsoft.Build.Evaluation.Project..ctor(XmlReader xmlReader, IDictionary2 globalProperties, String toolsVersion, ProjectCollection projectCollection)
```

Most helpful comment

@rainersigwald I was not, that fixed it. Is there documentation for the fact that you can't use the Project type without failing at runtime unless you reference Microsoft.Build.Runtime? Documentation like that would be extremely helpful.

All 10 comments

Figured out the problem. I need to explicitly add a nuget reference to "Microsoft.Build.Utilities.Core": "0.1.0-*". The nupkg for Microsoft.Build.Framework should specified Microsoft.Build.Utilities.Core as dependency. @jeffkl may already be working on that.

Well, that's confusing. There's no compile-of-MSBuild-time Framework->Utilities dependency; it's coming in from here:

C# s_availableStaticMethods.TryAdd("Microsoft.Build.Utilities.ToolLocationHelper", new Tuple<string, Type>("Microsoft.Build.Utilities.ToolLocationHelper, Microsoft.Build.Utilities.Core, Version=" + MSBuildConstants.CurrentAssemblyVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", null));

Which makes a type from Utilities available at evaluation time.

I think the right dependency is actually from Microsoft.Build to Microsoft.Build.Utilities.Core. But really it would be from our "runnable" package . . . @jeffkl thoughts on the best approach?

Yeah I see 2 solutions:

  1. Make Microsoft.Build depend on Microsoft.Build.Utilities.Core (just the NuGet package)

    1. This isn't ideal because there isn't an actual dependency

  2. Handle the type load error gracefully by maybe logging it only in the diagnostic log as a normal message.

    1. Not entirely sure the implications here but this is my vote.

@jeffkl wouldn't option 2 cause silent failures at eval time? We have a real runtime reference to that assembly, and if anything uses ToolLocationHelper static methods (and common targets do), that should really fail if it's not loadable.

These are the only instances I could find:

findstr /snpic:"ToolLocationHelper" *.targets
XMakeTasks\Microsoft.Common.CurrentVersion.targets:81:    <FrameworkPathOverride Condition="'$(FrameworkPathOverride)' == ''">$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToStandardLibraries($(TargetFrameworkIdentifier), $(TargetFrameworkVersion), $(TargetFrameworkProfile), $(PlatformTarget), $(TargetFrameworkRootPath)))</FrameworkPathOverride>
XMakeTasks\Microsoft.Common.CurrentVersion.targets:89:    <TargetPlatformSdkPath Condition=" '$(TargetPlatformSdkPath)' == ''">$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSDKLocation($(TargetPlatformIdentifier), $(TargetPlatformVersion)))</TargetPlatformSdkPath>
XMakeTasks\Microsoft.Common.CurrentVersion.targets:96:    <TargetPlatformDisplayName Condition="'$(TargetPlatformDisplayName)' == ''">$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSDKDisplayName($(TargetPlatformIdentifier), $(TargetPlatformVersion)))</TargetPlatformDisplayName>

Would any of these run in anymore?

This will be fixed by #1080. When the package is published, programs that want to do project evaluation or in-proc builds will reference Microsoft.Build.Runtime. This will pull in all of our assemblies as well as the core set of .props and .targets. We'll still need to work with partner teams to have packages created that contain stuff like compilers and extensions but it will at least get around the error found in this issue.

I'm hitting this. When should I expect the fix to RTM?

@jnm2 The fix was in the final MSBuild 15.1.548 packages (as well as several prereleases before that). Are you using the Microsoft.Build.Runtime package? If so, please open a new issue describing your scenario and the failure you're seeing.

@rainersigwald I was not, that fixed it. Is there documentation for the fact that you can't use the Project type without failing at runtime unless you reference Microsoft.Build.Runtime? Documentation like that would be extremely helpful.

Was this page helpful?
0 / 5 - 0 ratings