{"record":{"id":"81efe18dc5fe9e32","repo":"clockworklabs/SpacetimeDB","slug":"invalid-c-template-missing-net8-0-net10-0-target","errorCode":null,"errorMessage":"Invalid C# template: missing net8.0/net10.0 TargetFrameworks property","messagePattern":"Invalid C# template: missing net8\\.0/net10\\.0 TargetFrameworks property","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/cli/src/subcommands/init.rs","lineNumber":1887,"sourceCode":"        _ => unreachable!(\"unsupported .NET version should have been validated before init\"),\n    }\n}\n\nfn csharp_csproj_for_target(content: &str, dotnet_major: u8) -> anyhow::Result<String> {\n    let target_framework = match dotnet_major {\n        8 => \"net8.0\",\n        10 => \"net10.0\",\n        _ => unreachable!(\"unsupported .NET version should have been validated before init\"),\n    };\n    let target_framework_property = format!(\"<TargetFramework>{target_framework}</TargetFramework>\");\n    if content.contains(\"<TargetFrameworks>net8.0;net10.0</TargetFrameworks>\") {\n        return Ok(content.replace(\n            \"<TargetFrameworks>net8.0;net10.0</TargetFrameworks>\",\n            &target_framework_property,\n        ));\n    }\n\n    anyhow::bail!(\"Invalid C# template: missing net8.0/net10.0 TargetFrameworks property\")\n}\n\nfn configure_csharp_project_files(project_path: &Path, dotnet_major: u8) -> anyhow::Result<()> {\n    let global_json_path = project_path.join(\"global.json\");\n    std::fs::write(&global_json_path, csharp_global_json(dotnet_major))?;\n\n    let csproj_path = project_path.join(\"StdbModule.csproj\");\n    let csproj = std::fs::read_to_string(&csproj_path)?;\n    std::fs::write(&csproj_path, csharp_csproj_for_target(&csproj, dotnet_major)?)?;\n\n    Ok(())\n}\n\n/// Adds NativeAOT-LLVM project configuration to an existing C# .csproj file and creates NuGet.Config.\n///\n/// The configuration differs depending on the target .NET version:\n///\n/// **.NET 8 AOT** (`--native-aot`): Keeps `net8.0` TFM and adds explicit ILCompiler.LLVM 8.0.0-*","sourceCodeStart":1869,"sourceCodeEnd":1905,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/cli/src/subcommands/init.rs#L1869-L1905","documentation":"When configuring a C# project for a chosen .NET version, the CLI rewrites the template marker `<TargetFrameworks>net8.0;net10.0</TargetFrameworks>` (dual TFM) into a single `<TargetFramework>net8.0</TargetFramework>` or `net10.0`. If that literal marker is absent from StdbModule.csproj, the template is considered invalid and init aborts (init.rs:1887). This is an internal invariant over the embedded template, not user input.","triggerScenarios":"Re-running init/build in a directory whose StdbModule.csproj was hand-edited (e.g. TargetFrameworks changed or already collapsed to one TFM), or a CLI version whose embedded template format drifted from what this code expects.","commonSituations":"Manually editing TargetFrameworks to pin a TFM instead of using --dotnet-version; upgrading the spacetimedb CLI across a template-format change; partially overwritten or merge-conflicted project files.","solutions":["Delete the generated project directory and re-run `spacetime init` from scratch","Or restore the dual-TFM marker `<TargetFrameworks>net8.0;net10.0</TargetFrameworks>` in StdbModule.csproj and retry","Update (or pin) the spacetimedb CLI so the embedded template matches the version that generated the project","Going forward, change the TFM only via --dotnet-version, never by editing the csproj"],"exampleFix":"// before (StdbModule.csproj, hand-edited)\n<TargetFrameworks>net9.0</TargetFrameworks>\n// after (restore the marker the CLI rewrites)\n<TargetFrameworks>net8.0;net10.0</TargetFrameworks>","handlingStrategy":"type-guard","validationCode":"let csproj = std::fs::read_to_string(project.join(\"StdbModule.csproj\"))?;\nif !has_dual_tfm_marker(&csproj) {\n    anyhow::bail!(\"csproj lacks the net8.0/net10.0 marker; regenerate with spacetime init\");\n}","typeGuard":"fn has_dual_tfm_marker(csproj: &str) -> bool {\n    csproj.contains(\"<TargetFrameworks>net8.0;net10.0</TargetFrameworks>\")\n}","tryCatchPattern":null,"preventionTips":["Never hand-edit TargetFrameworks; use --dotnet-version","Re-init into a clean directory instead of over an edited one","Update the CLI and its templates together, and regenerate after upgrades"],"tags":["csharp","csproj","template","internal-invariant"],"backgroundTag":"template-validation-failed","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}