{"record":{"id":"b92cea7902394afa","repo":"clockworklabs/SpacetimeDB","slug":"the-selected-c-build-path-requires-the-net-desi","errorCode":null,"errorMessage":"The selected C# build path requires the .NET {desired_sdk_major} SDK, but the active SDK is .NET {active}.\nUpdate {} to select the .NET {desired_sdk_major} SDK, or run `spacetime init --dotnet-version {desired_sdk_major}` to create a project configured for this SDK.\nExpected global.json contents:\n{}","messagePattern":"The selected C# build path requires the \\.NET (.+?) SDK, but the active SDK is \\.NET (.+?)\\.\nUpdate (.+?) to select the \\.NET (.+?) SDK, or run `spacetime init --dotnet-version (.+?)` to create a project configured for this SDK\\.\nExpected global\\.json contents:\n(.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/cli/src/tasks/csharp.rs","lineNumber":261,"sourceCode":"                .unwrap_or_else(|| \"<unknown>\".to_string());\n            anyhow::bail!(\n                \"Unsupported .NET SDK version: {}. SpacetimeDB requires .NET SDK 8.0 or 10.0.\\n\\\n                 If you have multiple versions installed, configure your project using \\\n                 https://learn.microsoft.com/en-us/dotnet/core/tools/global-json, \\\n                 or use --dotnet-version to specify the target version explicitly.\",\n                selected_version\n            );\n        }\n    };\n\n    let desired_sdk_major = match build_path {\n        CsharpBuildPath::Net8Jit | CsharpBuildPath::Net8Aot => 8,\n        CsharpBuildPath::Net10Aot => 10,\n    };\n    let active_sdk_major = dotnet_version_str.as_deref().and_then(parse_major_version);\n    if active_sdk_major != Some(desired_sdk_major) {\n        let active = dotnet_version_str.as_deref().map(str::trim).unwrap_or(\"<unknown>\");\n        anyhow::bail!(\n            \"The selected C# build path requires the .NET {desired_sdk_major} SDK, but the active SDK is .NET {active}.\\n\\\n             Update {} to select the .NET {desired_sdk_major} SDK, or run `spacetime init --dotnet-version {desired_sdk_major}` to create a project configured for this SDK.\\n\\\n             Expected global.json contents:\\n{}\",\n            project_path.join(\"global.json\").display(),\n            dotnet_global_json(desired_sdk_major)?\n        );\n    }\n\n    // Manage the EXPERIMENTAL_WASM_AOT environment variable for MSBuild.\n    // - Net8Aot / Net10Aot: must SET it — the ILCompiler.LLVM.targets import in\n    //   SpacetimeDB.Runtime.targets is gated on this env var. Without it, the NativeAOT\n    //   toolchain is not activated and dotnet produces managed DLLs instead of a .wasm.\n    // - Net8Jit: must UNSET it — prevents MSBuild from incorrectly enabling NativeAOT mode\n    //   when the env var is set globally (e.g., in CI).\n    match &build_path {\n        CsharpBuildPath::Net8Aot | CsharpBuildPath::Net10Aot => {\n            // SAFETY: We are single-threaded at this point and no other code is reading\n            // this environment variable concurrently.","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/6dee26c6efc2856793e12b148a59742964f5d783/crates/cli/src/tasks/csharp.rs#L243-L279","documentation":"The C# build path was selected (JIT/AOT-LLVM paths require the .NET 8 SDK, the NativeAOT path requires .NET 10), but the SDK that `dotnet --version` actively resolves (when a global.json applies) has a different major. Rather than emit a wasm built by the wrong toolchain, the CLI aborts and prints the exact global.json contents it expects at <project>/global.json, including an init-command alternative.","triggerScenarios":"`spacetime build` on a C# project where the csproj/flags select the .NET 8 path but a project- or cwd-level global.json resolves SDK 10, or vice versa; also --dotnet-version 8 with an active SDK 10 global.json pin.","commonSituations":"Repo-level global.json pinning SDK 10 while the module targets net8.0; side-by-side SDK installs where the wrong one resolves; templates created before a version bump leaving a stale pin.","solutions":["Write the exact global.json the error prints into the project directory, e.g. {\"sdk\":{\"version\":\"8.0.100\",\"rollForward\":\"latestFeature\"}} for .NET 8.","Or reconfigure via `spacetime init --dotnet-version <8|10>` on a fresh project.","Or align the csproj <TargetFramework> (and --native-aot usage) with the SDK the global.json selects."],"exampleFix":"// before: project/global.json + csproj mismatch\n{\"sdk\":{\"version\":\"10.0.100\",\"rollForward\":\"latestMinor\"}}\n// <TargetFramework>net8.0</TargetFramework>\n// after: pin the SDK the build path needs\n{\"sdk\":{\"version\":\"8.0.100\",\"rollForward\":\"latestFeature\"}}","handlingStrategy":"validation","validationCode":"# Ensure the active SDK matches the target before building\nWANT=8\nglobal.json: {\"sdk\":{\"version\":\"${WANT}.0.100\",\"rollForward\":\"latestFeature\"}}\ndotnet --version | cut -d. -f1 | grep -qx \"$WANT\" || { echo \"active SDK != $WANT\" >&2; exit 1; }\nspacetime build","typeGuard":null,"tryCatchPattern":"On this failure, copy the exact global.json contents printed in the error message into <project>/global.json and re-run the build once","preventionTips":["Generate global.json with `dotnet new globaljson --roll-forward latestFeature` pinned to the TFM's major.","Keep csproj TargetFramework and the global.json pin in the same PR when bumping versions.","Use `spacetime init --dotnet-version` when scaffolding so the pin is created correctly from the start."],"tags":["csharp","dotnet","sdk-version","global-json","toolchain-mismatch"],"backgroundTag":"sdk-version-mismatch","analyzedSha":"6dee26c6efc2856793e12b148a59742964f5d783","analyzedAt":"2026-08-20T06:08:37.179Z","contentChangedAt":"2026-08-20T06:08:37.179Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}