build: intermittent CS0006 on the ubuntu CI leg (App.Shared ref assembly), root cause unproven

Aberta
#352 0 comentários 0 reações 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 1 dia

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
5/5
Tempo estimado
Mais de uma semana
Facilidade para iniciantes
25/100
Tipo de issue
Bug
Clareza
Razoavelmente clara
Status de atividade
Ativa
Stack de tecnologia
android, csharp
Domínio
build-system, ci-cd

Direção de pesquisa

Start with the Ubuntu Build step in the CI workflow and the Android multi-RID build settings; the issue identifies _AndroidBuildRuntimeIdentifiersInParallel as an untested candidate. First capture a failing binlog using repeated builds with fresh obj/ and bin/ directories, uploading the log on failure. Done means the intermittent CS0006 root cause is established and a fix is supported by evidence; the issue notes that no failing binlog has yet been captured.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

help wanted

Summary

The ubuntu-latest CI leg intermittently fails its Build step with:

CSC : error CS0006: Metadata file
  '/home/runner/work/lagebuch/lagebuch/src/LageBuch.App.Shared/obj/Release/net10.0/ref/LageBuch.App.Shared.dll'
  could not be found [/home/runner/work/lagebuch/lagebuch/src/LageBuch.App/LageBuch.App.csproj]

Seen once in ~25 runs surveyed (≈4%, single observation so the real rate could be ~1–10%): run 34987088319, attempt 1, the ubuntu leg of #327. A plain re-run cleared it with no code change.

Surfaced while fixing #326. Deliberately not fixed — see "Impact" for why this is filed rather than patched.

Impact (why this is low priority)

context builds App + App.Android in one MSBuild invocation? exposed
ubuntu CI leg (dotnet build LageBuch.sln) yes only here
windows CI leg no (Desktop.slnf excludes the Android head) no
release.yml windows/linux/macos jobs no (dotnet publish src/LageBuch.App/…, own runner) no
release.yml android job no (dotnet publish src/LageBuch.App.Android/…, own runner) no
make build / make ci no (desktop projects only) no
make build-all / make test-all yes yes (needs JDK ≤ 21)

Releases are structurally safe: each platform publishes a single project in its own job on its own runner, so LageBuch.App's csc and the Android inner build never run in the same invocation.

The failure is fail-stop, not corruption — the build dies, Test is skipped, no artifact is produced. It cannot ship a bad binary. The real cost is signal erosion: an intermittent red that is always "just re-run it" trains people to re-run reds without reading them.

Evidence gathered

Two MSBuild binlogs captured by temporarily adding -bl: plus a pinned actions/upload-artifact to the ubuntu leg, then replayed headlessly:

dotnet msbuild build.binlog -noconlog -flp:"logfile=diag.txt;verbosity=diagnostic"
  • baseline (main @ 9a0de65, no fix): run 35018637663
  • attempted fix (Directory.Build.targets): run 35017414253
❌ Hypothesis DISPROVEN — do not redo this

"Microsoft.Android.Sdk.AssemblyResolution.targets → _ResolveAssemblies re-invokes the Android head per RID with extra global properties; those flow down ProjectReference edges, giving LageBuch.App.Shared two MSBuild configurations writing the same obj/."

The SDK part is real — _ResolveAssemblies does inject _ComputeFilesToPublishForRuntimeIdentifiers, SkipCompilerExecution, _OuterOutputPath etc., once per RID (android-arm64;android-x64). But the conclusion does not follow. Both binlogs show exactly one configuration id per project:

baseline: App.Shared=11  AppLogic=6  Domain=9  Persistence=2  Sync=8
fixed:    App.Shared=10  AppLogic=7  Domain=9  Persistence=2  Sync=11

RuntimeIdentifier/SelfContained are stripped for RID-agnostic references and TargetFramework for single-TFM ones (Microsoft.Common.CurrentVersion.targets, _GetProjectReferenceTargetFrameworkProperties), so there is no second configuration to race. Leaked global properties are not the differentiator.

✅ What the evidence does support

The two RID inner builds each request the same configuration's default targets, and the scheduler can place them on different nodes — identically with and without the attempted fix:

project baseline attempted fix
App.Shared cfg 11:22 node 4, 11:24 node 4 cfg 10:22 node 4, 10:24 node 1
AppLogic cfg 6:42 node 3, 6:45 node 3 cfg 7:42 node 3, 7:44 node 1
Domain cfg 9:89 node 4, 9:94 node 1 cfg 9:82 node 2, 9:91 node 1
Persistence cfg 2:56 / 2:58 node 3 cfg 2:52 node 4, 2:54 node 1
Sync cfg 8:56 / 8:58 node 4 cfg 11:53 / 11:54 node 2

So the hazard is two concurrent builds of one configuration against one obj/ directory, not two configurations. Consistent with the error being CS0006 ("could not be found", i.e. a genuine unlink) rather than CS0009 — the only Delete in range is IncrementalClean, which reads and rewrites the shared …csproj.FileListAbsolute.txt. Not confirmed: no failing binlog was captured, only passing ones.

Unexplained residue

The attempted fix measurably halved the duplicated work for the two direct references — App.Shared went from two CopyFilesToOutputDirectory executions (TaskId 396, 792) to one (TaskId 397), AppLogic likewise — while Domain/Persistence/Sync still run twice. Why undefining properties changed anything, given the configuration was already single, is not explained. That is why it was not merged: "it helped and I don't know why" is not a rationale for a build-system change.

Next candidate (untested)

_AndroidBuildRuntimeIdentifiersInParallel=false — serialises the two RID inner builds so their reference-graph requests cannot overlap. An earlier analysis dismissed this on the reasoning that both inner builds collapse onto the same configuration and so serialising removes no contention; given the above, that reasoning looks exactly backwards — the contention is between those two.

Other options, with the caveat that several are symptom-level: build the Android head in its own sequential CI step; -m:1 on the ubuntu build (slow); ProduceReferenceAssembly=false (likely relocates CS0006 to CS0009 — not recommended).

To capture a failing binlog

Frequency is low, so loop the build inside one step with a fresh obj/+bin/ per iteration and upload on failure only. 15 iterations ≈ 46% chance of catching it, 30 ≈ 70%.

Revisit if

  • the rate climbs past roughly 1 in 10
  • a second project starts referencing the Android head
  • the ubuntu leg ever becomes release-blocking

The attempted fix is preserved in #330 (closed, with a correction comment).

Linguagem predominante
C#
Estrelas
1
Forks
3
Merge médio
7h 32min
PRs com merge (30d)
192

Preparar o ambiente

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de CodeForFire/lagebuch

Todas as issues de CodeForFire/lagebuch

Issues semelhantes

Mais issues de C#

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.