stride3d/stride · error · ArgumentException
' ' has no parent app directory.
Error message
'{runDirectory}' has no parent app directory. What it means
CrashSession.Load expects a run directory laid out as <base>/<app>/run-*. The run directory's parent must be the app directory; if the path has no parent (e.g. a filesystem root), the app id cannot be determined and the load aborts with this ArgumentException.
Solutions
- Pass the actual run directory (e.g. <base>/<app>/run-2024-01-01) to Load
- Guard the input: ensure Path.GetFullPath(runDirectory) has a parent before calling Load
- Fix any path-building code that points at the root or the base directory
Example fix
// before
var session = CrashSession.Load(storeBaseDir, dsn, false); // base dir, wrong level
// after
var runDir = Directory.GetDirectories(storeBaseDir, "*", SearchOption.AllDirectories)
.First(d => Path.GetFileName(d).StartsWith("run-"));
var session = CrashSession.Load(runDir, dsn, false); Defensive patterns
Strategy: validation
Validate before calling
var full = Path.GetFullPath(runDirectory);
if (Directory.GetParent(full) is null)
throw new ArgumentException($"'{runDirectory}' is not a valid run directory (no parent app directory)"); Type guard
bool IsLikelyRunDirectory(string path) =>
Path.GetFileName(path).StartsWith("run-") && Directory.GetParent(Path.GetFullPath(path)) != null; Try / catch
try { var session = CrashSession.Load(runDir, dsn, false); }
catch (ArgumentException e) when (e.Message.Contains("no parent app directory"))
{ /* correct the path or re-locate the run directory */ } Prevention
- Always pass the leaf run-* directory, never the base or app directory
- Discover run directories via Directory.EnumerateDirectories(base, "*") and pick run-* entries
- Assert the expected <base>/<app>/run-* layout in tests
When it happens
Trigger: Calling CrashSession.Load on a path that is a root directory or otherwise has no parent (Directory.GetParent returns null), instead of a run-* folder nested under an app directory.
Common situations: Passing the wrong level of the store hierarchy (the base or app directory, or "/") instead of a run directory; programmatic path building that concatenates incorrectly.
Related errors
- ' ' has no store base directory.
- Base path must be non-empty (use null for passthrough).
- assetItem must be an absolute path
- The relativePath argument is null or empty
- Expecting relative path
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/a9d54032e9a0bff7.
Report an issue: GitHub.
Appendix: source
Thrown at sources/crashreport/Stride.CrashReporter/CrashSession.cs:53
public IntPtr OwnerWindow { get; }
/// <summary>The deduped crash groups in this run that are not already suppressed.</summary>
public IReadOnlyList<StoredCrash> Groups { get; }
/// <summary>The run directory on disk (for a "reveal in file manager" that also keeps the files).</summary>
public string RunDirectory => run.Directory;
/// <summary>Crash sending was turned off at build time (StrideSentryDsn=false); offer no Send.</summary>
public bool IsDisabled => CrashReportSender.IsDisabled;
/// <summary>
/// Loads a run directory. The store layout is <c><base>/<app>/run-*</c>, so the app id and base
/// are the run's parent and grandparent — enough to also reach the app's suppression list.
/// </summary>
public static CrashSession Load(string runDirectory, string? dsnOverride, bool sessionScoped, int? hostProcessId = null, IntPtr ownerWindow = default)
{
var full = Path.GetFullPath(runDirectory);
var appDir = Directory.GetParent(full) ?? throw new ArgumentException($"'{runDirectory}' has no parent app directory.");
var baseDir = appDir.Parent ?? throw new ArgumentException($"'{runDirectory}' has no store base directory.");
var store = new CrashStore(appDir.Name, baseDir.FullName);
var run = CrashStore.OpenRun(full);
var dsn = CrashReportSender.ResolveDsn(dsnOverride);
// Defensive: capture already skips suppressed signatures, but never re-surface one that slipped through.
var groups = run.Read().Where(crash => !store.IsSuppressed(crash.Signature, crash.Version)).ToList();
return new CrashSession(store, run, dsn, sessionScoped, hostProcessId, ownerWindow, groups);
}
/// <summary>True when a full-memory dump of the crashed host can be written on demand: the host itself crashed
/// (<c>--host-pid</c>) and is still alive, blocked until this window closes. Windows only (dbghelp).</summary>
public bool CanDumpHost => hostProcessId is not null && OperatingSystem.IsWindows();
/// <summary>
/// Writes a full-memory dump of the waiting host to <paramref name="path"/>, with the report text beside it (a
/// dump only makes sense with its context). Strictly on demand: it can be several GB and is unscrubbed, so itView on GitHub (pinned to 96fad776d2)