Skip to content

Troubleshooting

Fievetl edited this page Jul 4, 2026 · 5 revisions

Troubleshooting

AtlasSetupException

Thrown when Atlas cannot prepare the test environment. Common causes:

  • VINTAGE_STORY is unset, or does not point at a folder containing VintagestoryAPI.dll. Atlas needs this to locate the game's binaries and libraries for assembly resolution.
  • A mod path in [assembly: AtlasMods(...)] (or [AtlasWorld(Mods = ...)]) does not resolve to an existing folder, .zip, or .dll relative to the test assembly's output directory. ModStager.Stage names every missing path in the exception message. See Mod Staging for path resolution rules.
  • Bridge staging copy failure. ModStager.StageBridge wraps any file system failure (locked file, permissions, missing source) copying AtlasBridge.dll into the scratch mods folder, naming both the source and destination paths and carrying the underlying file system error as the inner exception.
  • "Bridge mod did not start" or a mod loader rejection (bad modinfo.json, dependency resolution failure): the exception message includes the mod loader's own report. Check the embedded server's own logs, which land in the scenario's scratch data path (printed on failure; look for a temp directory created per test class under the OS temp folder).
  • Two hosts requested concurrently: HostRegistry.GetOrCreateAsync throws this if a second scenario class tries to get a host while one is already in flight. This should only happen if [assembly: CollectionBehavior(DisableTestParallelization = true)] is missing; see the one-live-server section below.

MissingMethodException (often inside Newtonsoft.Json or ServerConfig code)

If you installed Pixnop.Atlas.XUnit from NuGet, this almost always means VINTAGE_STORY was unset at build time: the package's buildTransitive target needs it to find the game's own Newtonsoft.Json.dll and copy it over the test SDK's transitive copy. For NuGet consumers this target runs automatically, no <Import> needed; set VINTAGE_STORY and rebuild.

If you are building Atlas from source instead (a ProjectReference rather than a PackageReference), the buildTransitive packaging step never runs, so you additionally need <Import Project=".../build/Atlas.E2E.targets" /> in the test project. Verify $(VintageStoryPath) resolves (it defaults from the VINTAGE_STORY environment variable), add the import if missing, rebuild, and re-run. See Getting Started.

VINTAGE_STORY unset

Both the build (compiling against VintagestoryAPI.dll) and the test run (booting the embedded server) need this environment variable. Set it once in your shell profile or CI environment to the folder containing VintagestoryAPI.dll:

export VINTAGE_STORY=/opt/vintagestory

ScenarioTimeoutException vs ServerCrashedException

  • ScenarioTimeoutException: thrown either by World.Until(...) when timeoutTicks elapses (tick-based, carries TicksWaited), or by the off-thread Watchdog when TimeoutMs elapses (wall-clock, independent of the server's own ticking). In the watchdog case, HostRegistry.MarkDead also marks the class host dead, since the game thread may still be running the abandoned scenario.
  • ServerCrashedException: thrown when the embedded server itself dies mid-scenario. The original crash is captured as the exception's inner exception and rethrown into the owning xUnit test; the class host is marked dead the same way, so remaining scenarios in the class fail fast with a clear message rather than cascading into opaque timeouts.

The VS shutdown NRE flake

Vintage Story 1.22.2 has a known shutdown flake in the embedded server: it occasionally throws a NullReferenceException from ServerSystemMonitor.Dispose() while tearing down. Atlas catches and swallows this specific failure at teardown; it does not affect scenario results and is not something a test author needs to work around. Tracked upstream as issue #8 for visibility.

Scenario hangs instead of failing

await World.Until(...) timeouts are tick-based, which only elapses while the server is actually ticking. If the server itself is stuck, the scenario's TimeoutMs watchdog (default 60 seconds of wall-clock time, set via [AtlasScenario(TimeoutMs = ...)]) is what actually fails the test. If a run hangs for substantially longer than that, check for a ConfigureAwait(false) in the scenario body: it detaches the continuation from the game thread's queue, which can produce hangs that the watchdog cannot observe correctly because the continuation itself never reaches the awaited task in the expected way. See Writing Scenarios for the full game-thread rule.

One-live-server violations

Atlas hosts at most one live server per process. If a second scenario class requests a host while another is still in flight, HostRegistry.GetOrCreateAsync throws AtlasSetupException with a message pointing at the missing [assembly: CollectionBehavior(DisableTestParallelization = true)] declaration. This attribute is required in every Atlas test assembly; without it, xUnit may attempt to run scenario classes concurrently, which Atlas cannot support (see Architecture for why: the embedded server relies on process-wide statics).

Clone this wiki locally