{"record":{"id":"004a10e030cb4898","repo":"microsoft/aspire","slug":"historical-dashboard-data-is-read-only","errorCode":null,"errorMessage":"Historical dashboard data is read-only.","messagePattern":"Historical dashboard data is read-only\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Aspire.Dashboard/ServiceClient/DashboardDataSource.cs","lineNumber":72,"sourceCode":"    internal DashboardRunDescriptor SelectedRun { get; private set; } = null!;\n\n    /// <summary>\n    /// Gets the telemetry repository for the selected dashboard run.\n    /// </summary>\n    public ITelemetryRepository TelemetryRepository { get; private set; } = null!;\n\n    /// <summary>\n    /// Gets the resource repository for the selected dashboard run.\n    /// </summary>\n    public IResourceRepository ResourceRepository { get; private set; } = null!;\n\n    internal bool IsReadOnly { get; private set; }\n\n    internal void EnsureWritable()\n    {\n        if (IsReadOnly)\n        {\n            throw new InvalidOperationException(\"Historical dashboard data is read-only.\");\n        }\n    }\n\n    DashboardRunDescriptor IDashboardRunSelection.SelectedRun => SelectedRun;\n\n    void IDashboardRunSelection.SelectRun(string? runId) => SelectRun(runId);\n\n    internal void SelectRun(string? runId)\n    {\n        var currentRun = _runStore.GetCurrentRun();\n        var selectedRun = runId is not null ? _runStore.GetRunById(runId, onlyCompatible: true) : null;\n        if (selectedRun is null)\n        {\n            if (!string.IsNullOrEmpty(runId))\n            {\n                _logger.LogWarning(\"Failed to switch to dashboard run '{RunId}' because it is no longer available.\", runId);\n            }\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Dashboard/ServiceClient/DashboardDataSource.cs#L54-L90","documentation":"DashboardDataSource tracks historical (loaded-from-disk) dashboard data in a read-only mode. EnsureWritable throws InvalidOperationException when code attempts to mutate a data source that was opened read-only, i.e. IsReadOnly is true because the data represents a past run rather than the live one.","triggerScenarios":"Calling EnsureWritable() (directly or via APIs that require a writable data source, e.g. adding telemetry or updating run state) on a DashboardDataSource whose IsReadOnly property is true — typically a historical run loaded from a persisted database.","commonSituations":"Writing telemetry or selection state into a historical run's data source opened from disk; a component that assumed it held the current run's data source but actually resolved a historical one from the pool.","solutions":["Check IsReadOnly before mutating and route writes to the current run's data source instead","Obtain a writable (current-run) DashboardDataSource from the pool for live data operations","If historical data legitimately must change (e.g. pinning), use the dedicated API (DashboardRunStore.SetRunPinned) rather than mutating the data source"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if (dataSource.IsReadOnly)\n{\n    // route write operations to the current run's data source instead\n}","typeGuard":"bool IsWritable(DashboardDataSource source) => !source.IsReadOnly;","tryCatchPattern":"try\n{\n    source.EnsureWritable();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"read-only\"))\n{\n    // fall back to the current run's writable data source\n}","preventionTips":["Check IsReadOnly before any mutation of historical data","Keep references to historical and current data sources clearly separated","Use dedicated store APIs (e.g. SetRunPinned) for historical state changes"],"tags":["dashboard","read-only","historical-data","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}