Bug 17224 - InvalidOperationException when using async stream operations
Summary: InvalidOperationException when using async stream operations
Alias: None
Product: Class Libraries
Classification: Mono
Component: System ()
Version: 3.2.x
Hardware: PC Windows
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
Depends on:
Reported: 2014-01-14 06:17 UTC by Øystein Krog
Modified: 2018-03-13 11:07 UTC (History)
2 users (show)

Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Øystein Krog 2014-01-14 06:17:39 UTC
When our app is under heavy load it tends to crash with this exception:

Jan 14 11:47:27 Initial-Force-Ipad-Mini ScAppiOS[7082] <Notice>: [ERROR] Application - Main(): Critical application error
	System.InvalidOperationException: The task has already completed
	  at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.SetException (System.Exception exception) [0x00000] in <filename unknown>:0 
	  at InitialForce.Utils.Extensions.StreamExtensions+<CopyToAsync>c__async5.MoveNext () [0x00000] in <filename unknown>:0 
	  at System.Threading.Tasks.SynchronizationContextContinuation.<Execute>m__0 (System.Object l) [0x00000] in <filename unknown>:0 
	  at MonoTouch.UIKit.UIKitSynchronizationContext+<Post>c__AnonStorey89.<>m__A8 () [0x00000] in <filename unknown>:0 
	  at MonoTouch.Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in <filename unknown>:0 
	  at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
	  at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00000] in <filename unknown>:0 
	  at ScApp.iOS.Application.Main (System.String[] args) [0x00000] in <filename unknown>:0 
Jan 14 11:47:32 Initial-Force-Ipad-Mini cplogd[7078] <Warning>: Exiting.

StreamExtension is fairly simple:
public static class StreamExtensions
        public static async Task CopyToAsync(this Stream source,
            Stream destination,
            IProgress<long> progress,
            CancellationToken cancellationToken = default(CancellationToken),
            int bufferSize = 0x1000)
            var buffer = new byte[bufferSize];
            int bytesRead;
            long totalRead = 0;
            while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
                await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken);
                totalRead += bytesRead;
                // progress support

I suspect this is a bug in the Tasks code.

=== Xamarin Studio ===

Version 4.3.1 (build 3)
Installation UUID: 1d6c823d-a024-4e68-999f-4570d68869f8
	Mono 3.2.5 ((no/964e8f0)
	GTK+ 2.24.20 theme: Raleigh
	GTK# (
	Package version: 302050000

=== Apple Developer Tools ===

Xcode 5.0.2 (3335.32)
Build 5A3005

=== Xamarin.Mac ===

Xamarin.Mac: Not Installed

=== Xamarin.Android ===

Version: 4.11.0 (Business Edition)
Android SDK: /Users/oysteinkrog/Library/Developer/Xamarin/android-sdk-mac_x86
	Supported Android versions:
		2.1   (API level 7)
		2.2   (API level 8)
		2.3   (API level 10)
		3.1   (API level 12)
		4.0   (API level 14)
		4.0.3 (API level 15)
Java SDK: /usr
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462-11M4609)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode)

=== Xamarin.iOS ===

Version: (Business Edition)
Hash: eac7b15
Build date: 2013-16-12 16:06:53-0500

=== Build Information ===

Release ID: 403010003
Git revision: bd21181650b29ffdb2c231beccb76097f3e7a399
Build date: 2014-01-09 00:12:45+0000
Xamarin addins: d56f838106065386208d53d6f1b34240068a919e

=== Operating System ===

Mac OS X 10.8.5
Darwin Oysteins-Mac.local 12.5.0 Darwin Kernel Version 12.5.0
    Sun Sep 29 13:33:47 PDT 2013
    root:xnu-2050.48.12~1/RELEASE_X86_64 x86_64
Comment 1 Marek Safar 2014-01-14 13:26:54 UTC
Any chance to get some sort of repro?
Comment 2 Øystein Krog 2014-01-15 09:48:40 UTC
I'll try to create repro Marek, but it may take me a little while.
Comment 3 Øystein Krog 2014-01-22 08:04:06 UTC
I've been able to find a workaround for this issue.
We use an ExplicitThreadScheduler (with a single thread) to run all queries against sqlite on a separate thread (for other/legacy reasons).
When I changed the tasks created on this scheduler (in sqlite.net async connection) to pass TaskCreationOptions.DenyChildAttach, it seems to have fixed the problem.
Unfortunately I'm not sure if I can spare the time to create a repro-case.

    /// <summary>Provides a scheduler that uses an explicit number of threads for scheduling tasks.</summary>
    public sealed class ExplicitThreadsTaskSchedulerIOS : TaskScheduler, IDisposable
        /// <summary>The threads used by the scheduler.</summary>
        private readonly List<Thread> _threads;

        /// <summary>Stores the queued tasks to be executed by our threads.</summary>
        private BlockingCollection<Task> _tasks;

        /// <summary>Initializes a new instance of the class with the specified concurrency level.</summary>
        /// <param name="numberOfThreads">The number of threads that should be created and used by this scheduler.</param>
        /// <param name="threadName">The name for the thread(s), useful for debugging etc.</param>
        public ExplicitThreadsTaskSchedulerIOS(int numberOfThreads, string threadName = null)
            // Validate arguments
            if (numberOfThreads < 1)
                throw new ArgumentOutOfRangeException("numberOfThreads");

            threadName = threadName ?? "ExplicitThreadsTaskSchedulerIOS";

            // Initialize the tasks collection
            _tasks = new BlockingCollection<Task>();

            // Create the threads to be used by this scheduler
            _threads = Enumerable.Range(0, numberOfThreads)
                .Select(i =>
                    var thread = new Thread(() =>
                        // Continually get the next task and try to execute it.
                        // This will continue until the scheduler is disposed and no more tasks remain.
                        foreach (Task t in _tasks.GetConsumingEnumerable())
                    thread.IsBackground = true;
                    thread.Name = string.Format("{0} {1}", threadName, i);
                    return thread;

            // Start all of the threads
            _threads.ForEach(t => t.Start());

        /// <summary>
        ///     Cleans up the scheduler by indicating that no more tasks will be queued.
        ///     This method blocks until all threads successfully shutdown.
        /// </summary>
        public void Dispose()
            if (_tasks != null)
                // Indicate that no new tasks will be coming in

                // Wait for all threads to finish processing tasks
                foreach (Thread thread in _threads)

                // Cleanup
                _tasks = null;

        /// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
        public override int MaximumConcurrencyLevel
            get { return _threads.Count; }

        /// <summary>Provides a list of the scheduled tasks for the debugger to consume.</summary>
        /// <returns>An enumerable of all tasks currently scheduled.</returns>
        protected override IEnumerable<Task> GetScheduledTasks()
            // Serialize the contents of the blocking collection of tasks for the debugger
            return _tasks.ToArray();

        /// <summary>Queues a Task to be executed by this scheduler.</summary>
        /// <param name="task">The task to be executed.</param>
        protected override void QueueTask(Task task)
            // Push it into the blocking collection of tasks

        /// <summary>Determines whether a Task may be inlined.</summary>
        /// <param name="task">The task to be executed.</param>
        /// <param name="taskWasPreviouslyQueued">Whether the task was previously queued.</param>
        /// <returns>true if the task was successfully inlined; otherwise, false.</returns>
        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
            // Try to inline if the current thread is one of our internal threads
            return _threads.Contains(Thread.CurrentThread) && TryExecuteTask(task);
Comment 4 Marek Safar 2014-01-27 05:13:20 UTC
Mono master has fixes which are not part of and may well fix the issue. You'll probably have to wait for 7.0.7 and try again if we don't have way to reproduce the issue and verify it's resolved
Comment 5 Marek Safar 2018-03-13 11:07:22 UTC
We have not received the requested information. If you are still experiencing this issue please provide all the requested information and reopen the bug report.

Thank you!