One common mistake has to do with the implementation of CompletedSynchronously property of IAsyncResult. People writing their own classes implementing IAsyncResult need to be careful returning the correct value and neither ‘always true’ nor ‘always false’ is a good idea in most cases. According to the design of the async API pattern, CompletedSynchronously is supposed to be 'true' if the AsynCallback is called from inside the ‘begin’ method, on the same thread. In all other cases CompletedSynchronously must be 'false'. An incorrect value could lead to deadlocks.

The reason for existence of CompletedSynchronously property in IAsyncResult is to allow callers of asynchronous components chain asynchronous operations (completed synchronously) without consuming stack and avoid keeping objects alive longer than needed. Without this knowledge(whether or not an async operation completed synchronously) the caller has to call the next operation from the callback of the previous one:

Caller
    Component1.BeginMethod
        AsyncCallback
            Component1.EndMethod
            Component2.BeginMethod
                AsyncCallback
                    Component2.EndMethod
Knowing that an operation completed synchronously, the caller could call the next operation after the begin method of the (synchronously completed) previous operation returns.
Caller
    Component1.BeginMethod
        AsyncCallback
    Component1.EndMethod
    Component2.BeginMethod
        AsyncCallback
    Component2.EndMethod
Sometimes people complete an asynchronous operation synchronously in case of an error starting it. A better approach is to throw an exception from the ‘begin’ method. The rule is that if the asynchronous operation could not be started (as a result of an error) ‘begin’ method should throw.