{"record":{"id":"650fc1e20d9046d7","repo":"dotnet/BenchmarkDotNet","slug":"invalid-tfm-0","errorCode":null,"errorMessage":"Invalid TFM: '{0}'","messagePattern":"Invalid TFM: '(.+?)'","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/BenchmarkDotNet/Toolchains/NativeAot/Generator.cs","lineNumber":267,"sourceCode":"\n                \"\"\";\n\n            string directoryName = Path.GetDirectoryName(artifactsPaths.ProjectFilePath)!;\n            if (directoryName == null)\n                throw new InvalidOperationException($\"Can't get directory of projectFilePath ('{artifactsPaths.ProjectFilePath}')\");\n\n            return new(File.WriteAllTextAsync(Path.Combine(directoryName, GeneratedRdXmlFileName), content, cancellationToken));\n        }\n\n        private string GetCurrentInstructionSet(Platform platform)\n            => string.Join(\",\", GetCurrentProcessInstructionSets(platform));\n\n        // based on https://github.com/dotnet/runtime/tree/v10.0.0-rc.1.25451.107/src/coreclr/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt\n        private IEnumerable<string> GetCurrentProcessInstructionSets(Platform platform)\n        {\n            if (!ConfigParser.TryParse(TargetFrameworkMoniker, out RuntimeMoniker runtimeMoniker))\n            {\n                throw new NotSupportedException($\"Invalid TFM: '{TargetFrameworkMoniker}'\");\n            }\n\n            // TFM is the MSBuild moniker, not the BDN moniker, so it resolves to Net10_0 instead of NativeAot10_0.\n            // TODO: Get the correct moniker from the NativeAotRuntime (#2609)\n            runtimeMoniker += RuntimeMoniker.NativeAot70 - RuntimeMoniker.Net70;\n\n            if (platform == RuntimeInformation.GetCurrentPlatform() // \"native\" does not support cross-compilation (so does BDN for now)\n                && runtimeMoniker >= RuntimeMoniker.NativeAot80)\n            {\n                yield return \"native\"; // added in .NET 8 https://github.com/dotnet/runtime/pull/87865\n                yield break;\n            }\n\n            switch (platform)\n            {\n                case Platform.X86:\n                case Platform.X64:\n                    if (HardwareIntrinsics.IsX86BaseSupported) yield return \"base\";","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/dotnet/BenchmarkDotNet/blob/b515068b61ad1c9c9aa938b8ece4af1e7d6d85a3/src/BenchmarkDotNet/Toolchains/NativeAot/Generator.cs#L249-L285","documentation":"Thrown by the NativeAOT generator when it cannot parse the configured TargetFrameworkMoniker (TFM) string into a RuntimeMoniker enum value. The generator needs the moniker to decide which hardware instruction sets to enumerate for the native compilation. ConfigParser.TryParse strips any '-suffix', then tries Enum.TryParse with dots removed (e.g. 'net80') and with dots replaced by underscores (e.g. 'net_8_0'); if neither matches a RuntimeMoniker value, NotSupportedException is thrown.","triggerScenarios":"Called from GetCurrentProcessInstructionSets(Platform) → GetCurrentInstructionSet, which runs during NativeAOT csproj generation (Generate or its project-building path). The TFM string originates from the NativeAotToolchain / builder's .TargetFrameworkMoniker(...) call. Any string that does not map to a RuntimeMoniker enum member (after stripping after '-') triggers it: typos like 'net8', unsupported previews like 'net12.0', or arbitrary custom strings.","commonSituations":"Passing .TargetFrameworkMoniker(\"net8\") instead of \"net8.0\". Using a future TFM that the installed BDN version does not yet know. Constructing a NativeAotToolchain with a hand-typed moniker that doesn't exactly match an enum entry. Upgrading the .NET SDK to a preview TFM without upgrading BDN.","solutions":["Use an exact, supported TFM string matching a RuntimeMoniker enum value: \"net8.0\", \"net9.0\", \"net10.0\", \"net11.0\" (check the RuntimeMoniker enum for your BDN version)","Avoid passing a raw TFM via the builder; instead use a recognized RuntimeMoniker through NativeAotRuntime (e.g. NativeAotRuntime.NativeAot80) so the correct MsBuildMoniker is supplied","Upgrade BenchmarkDotNet to a release that adds support for the TFM you are targeting"],"exampleFix":"// before\nvar toolchain = NativeAotToolchain.CreateBuilder()\n    .UseNuGet()\n    .TargetFrameworkMoniker(\"net8\")  // wrong: no matching RuntimeMoniker\n    .ToToolchain();\n\n// after (exact TFM)\nvar toolchain = NativeAotToolchain.CreateBuilder()\n    .UseNuGet()\n    .TargetFrameworkMoniker(\"net8.0\")\n    .ToToolchain();\n\n// after (preferred: use a known runtime)\nvar toolchain = NativeAotToolchain.CreateBuilder()\n    .UseNuGet()\n    .TargetFrameworkMoniker(RuntimeMoniker.NativeAot80.MsBuildMoniker())\n    .ToToolchain();","handlingStrategy":"validation","validationCode":"// Validate a TFM string resolves to a RuntimeMoniker before configuring the NativeAOT toolchain.\nusing BenchmarkDotNet.ConsoleArguments;\nusing BenchmarkDotNet.Environments;\n\nstatic string EnsureValidTfm(string tfm)\n{\n    if (!ConfigParser.TryParse(tfm, out RuntimeMoniker _))\n        throw new ArgumentException(\n            $\"TFM '{tfm}' does not map to any RuntimeMoniker. Use e.g. 'net8.0', 'net9.0', 'net10.0'.\",\n            nameof(tfm));\n    return tfm;\n}\n\nvar tfm = EnsureValidTfm(myTfm);\nvar toolchain = NativeAotToolchain.CreateBuilder()\n    .UseNuGet()\n    .TargetFrameworkMoniker(tfm)\n    .ToToolchain();","typeGuard":null,"tryCatchPattern":"// Catch NotSupportedException around benchmark execution if the TFM is user-supplied.\ntry { BenchmarkRunner.Run<MyBench>(); }\ncatch (NotSupportedException ex) when (ex.Message.Contains(\"Invalid TFM\"))\n{\n    throw new ArgumentException($\"Configured TargetFrameworkMoniker is not recognized by BDN: {ex.Message}\", ex);\n}","preventionTips":["Always pass exact MSBuild TFMs (net8.0, net9.0, net10.0, net11.0) — never shortened forms like 'net8'.","Prefer NativeAotRuntime constants (e.g. NativeAotRuntime.NativeAot80) over hand-typed moniker strings.","Upgrade BDN alongside .NET SDK upgrades so new TFMs are recognized by ConfigParser.TryParse."],"tags":["nativeaot","tfm","runtime-moniker","instruction-set","toolchain"],"backgroundTag":null,"analyzedSha":"b515068b61ad1c9c9aa938b8ece4af1e7d6d85a3","analyzedAt":"2026-08-13T19:12:24.196Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}