microsoft/aspire · error

Dashboard run ' ' is no longer available.

Error message

Dashboard run '{run.RunId}' is no longer available.

What it means

SetRunPinned updates a historical run's pinned flag, first resolving the run's stored record via GetRunById. It throws InvalidOperationException when no stored run exists for the given run ID — the run has been deleted or pruned from the store, so pinning cannot proceed.

Solutions

  1. Re-list available runs and confirm the run ID exists before pinning
  2. Catch the exception and refresh the run list in the caller (the run was deleted externally)
  3. Avoid pinning runs that are not present in the store's current run inventory

Example fix

// before
store.SetRunPinned(run, isPinned: true);

// after
if (store.GetRunById(run.RunId, onlyCompatible: false) is not null)
{
    store.SetRunPinned(run, isPinned: true);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (store.GetRunById(run.RunId, onlyCompatible: false) is null)
{
    // run no longer exists; skip pinning and refresh the run list
}

Try / catch

try
{
    store.SetRunPinned(run, isPinned: true);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("no longer available"))
{
    runs = store.ListRuns(); // refresh stale UI state
}

Prevention

When it happens

Trigger: Calling SetRunPinned with a DashboardRunDescriptor whose RunId is no longer present in the run store (GetRunById returned null, even with onlyCompatible:false).

Common situations: A UI or automation holds a reference to a run that was concurrently deleted/expired by retention cleanup; pinning a historical run after the store was disposed or its directory removed; stale run descriptor from a previous dashboard session.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/9ffcb708d0e01fae. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Dashboard/ServiceClient/DashboardRunStore.cs:284

    public DashboardPersistenceMode PersistenceMode { get; }
    public bool SupportsRunSelection => PersistenceMode == DashboardPersistenceMode.Run;

    public IReadOnlyList<DashboardRunDescriptor> GetRuns() =>
        _runs.Value.Where(run => !run.IsPruned).ToArray();

    public DashboardRunDescriptor GetCurrentRun() => GetRuns().Single(run => run.IsCurrent);

    public DashboardRunDescriptor? GetRunById(string runId, bool onlyCompatible) =>
        GetRuns().SingleOrDefault(run =>
            (!onlyCompatible || run.IsCompatible) &&
            string.Equals(run.RunId, runId, StringComparison.Ordinal));

    public void SetRunPinned(DashboardRunDescriptor run, bool isPinned)
    {
        var storedRun = GetRunById(run.RunId, onlyCompatible: false);
        if (storedRun is null)
        {
            throw new InvalidOperationException($"Dashboard run '{run.RunId}' is no longer available.");
        }

        var runDirectory = Path.GetDirectoryName(storedRun.DatabasePath)!;
        lock (_runStateLock)
        {
            // The current run has the store's lifetime lock, and a selected historical run has a lease.
            // Only an unselected historical run needs a temporary lock while its metadata is updated.
            using var runLock = storedRun.IsCurrent || storedRun.IsLeased
                ? null
                : TryOpenRunLock(runDirectory)
                    ?? throw new InvalidOperationException($"Dashboard run '{storedRun.RunId}' is no longer available.");
            UpdatePinnedState(storedRun, runDirectory, isPinned);
        }
    }

    private void UpdatePinnedState(DashboardRunDescriptor run, string runDirectory, bool isPinned)
    {
        var metadataPath = Path.Combine(runDirectory, "run.json");

View on GitHub (pinned to 25830f84bd)