clockworklabs/SpacetimeDB · error · anyhow::Error

Invalid C# template: missing net8.0/net10.0…

Error message

Invalid C# template: missing net8.0/net10.0 TargetFrameworks property

What it means

While pinning the .NET version, the CLI rewrites the csproj by finding the exact marker `<TargetFrameworks>net8.0;net10.0</TargetFrameworks>` and replacing it with a single `<TargetFramework>net8.0|net10.0</TargetFramework>`. If the embedded C# template's csproj no longer contains that marker (template drift, tampered install, or a modified template in a fork), rewriting fails and init aborts.

Solutions

  1. Update/reinstall the official CLI so embedded templates match the rewrite logic
  2. Falling back to the default (no --dotnet-version) lets generation proceed with the multi-target csproj
  3. If building from source, restore the marker in templates or update the matcher, then rebuild
  4. Report as a bug if reproducible on an official release
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: Using --lang csharp with --dotnet-version on a CLI whose embedded template csproj changed shape; forked CLI with edited templates; partially updated install.

Common situations: Template refactors between CLI versions; custom forks that restyle the csproj; corrupted installation.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@fdd647dfac (2026-08-20). Data as JSON: /api/errors/81efe18dc5fe9e32. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/subcommands/init.rs:1891

        _ => unreachable!("unsupported .NET version should have been validated before init"),
    }
}

fn csharp_csproj_for_target(content: &str, dotnet_major: u8) -> anyhow::Result<String> {
    let target_framework = match dotnet_major {
        8 => "net8.0",
        10 => "net10.0",
        _ => unreachable!("unsupported .NET version should have been validated before init"),
    };
    let target_framework_property = format!("<TargetFramework>{target_framework}</TargetFramework>");
    if content.contains("<TargetFrameworks>net8.0;net10.0</TargetFrameworks>") {
        return Ok(content.replace(
            "<TargetFrameworks>net8.0;net10.0</TargetFrameworks>",
            &target_framework_property,
        ));
    }

    anyhow::bail!("Invalid C# template: missing net8.0/net10.0 TargetFrameworks property")
}

fn configure_csharp_project_files(project_path: &Path, dotnet_major: u8) -> anyhow::Result<()> {
    let global_json_path = project_path.join("global.json");
    std::fs::write(&global_json_path, csharp_global_json(dotnet_major))?;

    let csproj_path = project_path.join("StdbModule.csproj");
    let csproj = std::fs::read_to_string(&csproj_path)?;
    std::fs::write(&csproj_path, csharp_csproj_for_target(&csproj, dotnet_major)?)?;

    Ok(())
}

fn csproj_has_package_reference(content: &str, include: &str, version: &str) -> bool {
    fn element_has_package_reference(element: &xmltree::Element, include: &str, version: &str) -> bool {
        if element.name == "PackageReference"
            && element.attributes.get("Include").map(String::as_str) == Some(include)
            && element.attributes.get("Version").map(String::as_str) == Some(version)

View on GitHub (pinned to fdd647dfac)