{"record":{"id":"0285ce6f4f472c72","repo":"clockworklabs/SpacetimeDB","slug":"invalid-csproj-file-missing-project-tag","errorCode":null,"errorMessage":"Invalid .csproj file: missing </Project> tag","messagePattern":"Invalid \\.csproj file: missing </Project> tag","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/cli/src/subcommands/init.rs","lineNumber":1933,"sourceCode":"    if !csproj_path.exists() {\n        anyhow::bail!(\"Could not find StdbModule.csproj at {}\", csproj_path.display());\n    }\n\n    let content = std::fs::read_to_string(&csproj_path)?;\n\n    let new_content = if dotnet_major == Some(8) {\n        // .NET 8 AOT: keep net8.0 TFM, add explicit ILCompiler.LLVM package references.\n        let native_aot_config = r#\"\n  <ItemGroup Condition=\"'$(EXPERIMENTAL_WASM_AOT)' == '1'\">\n    <PackageReference Include=\"Microsoft.DotNet.ILCompiler.LLVM\" Version=\"8.0.0-*\" />\n    <PackageReference Include=\"runtime.$(NETCoreSdkPortableRuntimeIdentifier).Microsoft.DotNet.ILCompiler.LLVM\" Version=\"8.0.0-*\" />\n  </ItemGroup>\n\"#;\n        if let Some(pos) = content.rfind(\"</Project>\") {\n            let (before, after) = content.split_at(pos);\n            format!(\"{}{}{}\", before.trim_end(), native_aot_config, after)\n        } else {\n            anyhow::bail!(\"Invalid .csproj file: missing </Project> tag\");\n        }\n    } else {\n        // .NET 10 AOT: directly set TFM to net10.0 (no conditional needed).\n        // ILCompiler.LLVM comes transitively via the SpacetimeDB.Runtime NuGet package.\n        content.replace(\n            \"<TargetFramework>net8.0</TargetFramework>\",\n            \"<TargetFramework>net10.0</TargetFramework>\",\n        )\n    };\n\n    std::fs::write(&csproj_path, new_content)?;\n    println!(\n        \"{} Added NativeAOT-LLVM project configuration to {}\",\n        \"✓\".green(),\n        csproj_path.display()\n    );\n\n    // Create NuGet.Config with the dotnet-experimental feed required for ILCompiler.LLVM packages","sourceCodeStart":1915,"sourceCodeEnd":1951,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/cli/src/subcommands/init.rs#L1915-L1951","documentation":"Injecting the NativeAOT ItemGroup splits the csproj at the last `</Project>` tag so the new ItemGroup can be inserted before it. A csproj without that closing tag is malformed XML, and the CLI refuses to write AOT configuration into it (init.rs:1933).","triggerScenarios":"Building/publishing with --native-aot when StdbModule.csproj was truncated, badly merged, or hand-edited so the `</Project>` closing tag disappeared.","commonSituations":"Unresolved git merge conflicts inside the csproj; codegen or editors mangling the file; partial writes from a crashed process.","solutions":["Open the csproj at the printed path and re-add the closing `</Project>` tag, then retry","Or regenerate: delete the directory, re-run `spacetime init`, and reapply your changes","Validate the XML (`xmllint --noout StdbModule.csproj` or `dotnet build`) before retrying publish"],"exampleFix":"// before (StdbModule.csproj, truncated)\n  </ItemGroup>\n// after\n  </ItemGroup>\n</Project>","handlingStrategy":"validation","validationCode":"xmllint --noout \"$PROJECT_DIR/StdbModule.csproj\" || { echo 'csproj is not well-formed XML' >&2; exit 2; }","typeGuard":"fn has_project_close_tag(csproj: &str) -> bool {\n    csproj.rfind(\"</Project>\").is_some()\n}","tryCatchPattern":null,"preventionTips":["Treat the csproj as generated: change the TFM via --dotnet-version, not edits","Resolve merge conflicts in StdbModule.csproj before publishing","Validate the XML after any tool touches the csproj"],"tags":["csproj","native-aot","malformed-xml"],"backgroundTag":"malformed-project-file","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}