{"record":{"id":"d7a2c2be8be0e292","repo":"microsoft/semantic-kernel","slug":"cannot-access-a-disposed-object","errorCode":null,"errorMessage":"Cannot access a disposed object.","messagePattern":"Cannot access a disposed object\\.","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Agents/Orchestration/OrchestrationResult.cs","lineNumber":66,"sourceCode":"    /// </summary>\n    public TopicId Topic => this._context.Topic;\n\n    /// <summary>\n    /// Asynchronously retrieves the orchestration result value.\n    /// If a timeout is specified, the method will throw a <see cref=\"TimeoutException\"/>\n    /// if the orchestration does not complete within the allotted time.\n    /// </summary>\n    /// <param name=\"timeout\">An optional <see cref=\"TimeSpan\"/> representing the maximum wait duration.</param>\n    /// <param name=\"cancellationToken\">A cancellation token that can be used to cancel the operation.</param>\n    /// <returns>A <see cref=\"ValueTask{TValue}\"/> representing the result of the orchestration.</returns>\n    /// <exception cref=\"ObjectDisposedException\">Thrown if this instance has been disposed.</exception>\n    /// <exception cref=\"TimeoutException\">Thrown if the orchestration does not complete within the specified timeout period.</exception>\n    public async ValueTask<TValue> GetValueAsync(TimeSpan? timeout = null, CancellationToken cancellationToken = default)\n    {\n#if !NETCOREAPP\n        if (this._isDisposed)\n        {\n            throw new ObjectDisposedException(this.GetType().Name);\n        }\n#else\n        ObjectDisposedException.ThrowIf(this._isDisposed, this);\n#endif\n\n        this._logger.LogOrchestrationResultAwait(this.Orchestration, this.Topic);\n\n        if (timeout.HasValue)\n        {\n#if NET\n            try\n            {\n                await this._completion.Task.WaitAsync(timeout.Value, cancellationToken).ConfigureAwait(false);\n            }\n            catch (TimeoutException)\n            {\n                this._logger.LogOrchestrationResultTimeout(this.Orchestration, this.Topic);\n                throw;","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/dotnet/src/Agents/Orchestration/OrchestrationResult.cs#L48-L84","documentation":"Thrown by GetValueAsync (and Cancel) on OrchestrationResult<TValue> after the instance has been disposed. OrchestrationResult is IDisposable (it owns a CancellationTokenSource and a TaskCompletionSource); once Dispose runs, _isDisposed is true and any further access throws ObjectDisposedException.","triggerScenarios":"using var result = orchestration.InvokeAsync(...); await result.GetValueAsync(); where Dispose fires before GetValueAsync completes (e.g. via 'using' scoping, or explicit Dispose before await), or reusing a disposed result.","commonSituations":"Wrapping the result in a 'using' block and awaiting outside that block; calling GetValueAsync twice across a Dispose; DI scopes disposing the result early.","solutions":["Call GetValueAsync before the result is disposed — do not wrap it in 'using' if you await afterwards.","Avoid calling Dispose until you have retrieved the value.","Track disposal state so a disposed result is not accessed again."],"exampleFix":"// before\nusing var result = await orchestration.InvokeAsync(input);\nvar value = await result.GetValueAsync(); // 'using' may dispose before use on some flows\n\n// after — dispose only after retrieving the value\nvar result = await orchestration.InvokeAsync(input);\ntry { var value = await result.GetValueAsync(); }\nfinally { result.Dispose(); }","handlingStrategy":"validation","validationCode":"// Retrieve the value before disposing; dispose only afterwards\nvar result = await orchestration.InvokeAsync(input);\ntry { var value = await result.GetValueAsync(); }\nfinally { result.Dispose(); }","typeGuard":null,"tryCatchPattern":"try { return await result.GetValueAsync(); }\ncatch (ObjectDisposedException) { /* result already disposed; recreate orchestration */ throw; }","preventionTips":["Do not wrap OrchestrationResult in 'using' when you await after the block.","Call Dispose only after GetValueAsync has returned.","Track disposal state to avoid double-use across async flows."],"tags":["orchestration","lifecycle","disposal","async","agents"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}