dotnet / dotnet/sdk

Race Condition in StaticWebAssets with Multi-Targeting and TypeScript Compilation

Open
#52,014 6 comments 2 reactions 0 assignees View on GitHub
Area-AspNetCore StaticWebAssets
Dominant language
C#
Stars
3.2k
Forks
1.3k
PR merge metrics
PR metrics pending

Description

### Description

When using multi-targeting (`net8.0;net9.0`) in a Razor Class Library project that compiles TypeScript files via `Microsoft.TypeScript.MSBuild`, a race condition occurs during `dotnet build`. The `ResolveProjectStaticWebAssets` target sometimes attempts to resolve static web assets before the TypeScript compiler has finished writing the compiled `.js` files to disk, resulting in an `InvalidOperationException`.

The error only manifests when multi-targeting is enabled. With a single target framework, the build succeeds consistently.

### Reproduction Steps

1. Create a Razor Class Library project with multi-targeting:
```xml
net8.0;net9.0
```
2. Add TypeScript compilation via `Microsoft.TypeScript.MSBuild` package
3. Configure `tsconfig.json` to output compiled files to `wwwroot/js/dist`:
```json
{
"compilerOptions": {
"rootDir": "wwwroot/ts",
"outDir": "wwwroot/js/dist"
}
}
```
4. Add a TypeScript file in `wwwroot/ts/` (e.g., `test.ts`)
5. Run `dotnet build` multiple times **on Windows**
6. The error occurs non-deterministically (race condition)

**Sample repository:** https://github.com/loop8ack/Dotnet.Issue120620.Reproduction

### Expected behavior

The build should succeed consistently.

### Actual behavior

The build fails intermittently with:

```
Microsoft.NET.Sdk.StaticWebAssets.targets(679,5): Error : System.InvalidOperationException: No file exists for the asset at either location 'D:\Source\...\wwwroot\js\dist\test.js' or 'wwwroot\js\dist\test.js'.
at Microsoft.AspNetCore.StaticWebAssets.Tasks.StaticWebAsset.ResolveFile(String identity, String originalItemSpec)
at Microsoft.AspNetCore.StaticWebAssets.Tasks.DefineStaticWebAssets.ResolveFileDetails(String originalItemSpec, String identity)
at Microsoft.AspNetCore.StaticWebAssets.Tasks.DefineStaticWebAssets.Execute()
```

### Regression?

Unknown. I have not tested whether this occurs in earlier SDK versions.

### Known Workarounds

I have implemented a workaround using file-based locking to serialize access to the `ResolveProjectStaticWebAssets` target:

```xml

```

This forces sequential execution of 'ResolveProjectStaticWebAssets' across target frameworks and appears to work reliably. However:

- This is a hack that shouldn't be necessary
- It adds build time overhead
- It requires custom MSBuild task implementations

**Alternative workaround:** Remove multi-targeting (use only a single ``) - this eliminates the race condition but is not always feasible.

### Configuration

- **SDK Version:** 9.0.304
- **OS:** Windows 11 (issue does not occur under Linux)
- **Project Type:** Razor Class Library (`Microsoft.NET.Sdk.Razor`)
- **Packages:**
- `Microsoft.AspNetCore.Components.Web` (8.0.* and 9.0.* depending on framework)
- `Microsoft.TypeScript.MSBuild` 5.8.3

**Project file excerpt:**
```xml


net8.0;net9.0








```

### Other information

The issue appears to be a timing/ordering problem in the MSBuild target execution graph when multiple target frameworks are being built:

1. With multi-targeting, MSBuild builds each target framework in parallel or in rapid succession
2. The TypeScript compilation (`CompileTypeScript` target) runs as part of the build process
3. The `ResolveProjectStaticWebAssets` target attempts to enumerate and validate static web assets
4. There is insufficient dependency declaration or synchronization between these targets
5. When building multiple frameworks, `ResolveProjectStaticWebAssets` from one framework build can race with `CompileTypeScript` from another, or the file system operations are not fully synchronized

The race is confirmed by the non-deterministic nature of the failure — it does not occur on every build, only sometimes.

The race condition appears to be Windows-specific. Testing under WSL does not reproduce the issue; conversely, the file-locking workaround causes problems on WSL/Linux.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.