         // immediately. If this leaves us with zero streams, the connection is fullyQuiesced. Otherwise, we are quiescing.
         switch self.state {
         case .prefaceSent(var state):
-            let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
-            let newState = QuiescingPrefaceSentState(fromPrefaceSent: state, lastStreamID: lastStreamID)
-            self.state = .quiescingPrefaceSent(newState)
-            return result
+            return self.avoidingStateMachineCoW { newState in
+                let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
+                let newStateData = QuiescingPrefaceSentState(fromPrefaceSent: state, lastStreamID: lastStreamID)
+                newState = .quiescingPrefaceSent(newStateData)
+                return result
+            }
 
         case .active(var state):
-            let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
-            let newState = LocallyQuiescedState(fromActive: state, lastRemoteStreamID: lastStreamID)
-            self.state = .locallyQuiesced(newState)
-            self.closeIfNeeded(newState)
-            return result
+            return self.avoidingStateMachineCoW { newState in
+                let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
+                let newStateData = LocallyQuiescedState(fromActive: state, lastRemoteStreamID: lastStreamID)
+                newState = .locallyQuiesced(newStateData)
+                newState.closeIfNeeded(newStateData)
+                return result
+            }
 
         case .locallyQuiesced(var state):
-            let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
-            self.state = .locallyQuiesced(state)
-            self.closeIfNeeded(state)
-            return result
+            return self.avoidingStateMachineCoW { newState in
+                let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
+                newState = .locallyQuiesced(state)
+                newState.closeIfNeeded(state)
+                return result
+            }
 
         case .remotelyQuiesced(var state):
-            let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
-            let newState = BothQuiescingState(fromRemotelyQuiesced: state, lastRemoteStreamID: lastStreamID)
-            self.state = .bothQuiescing(newState)
-            self.closeIfNeeded(newState)
-            return result
+            return self.avoidingStateMachineCoW { newState in
+                let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
+                let newStateData = BothQuiescingState(fromRemotelyQuiesced: state, lastRemoteStreamID: lastStreamID)
+                newState = .bothQuiescing(newStateData)
+                newState.closeIfNeeded(newStateData)
+                return result
+            }
 
         case .bothQuiescing(var state):
-            let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
-            self.state = .bothQuiescing(state)
-            self.closeIfNeeded(state)
-            return result
+            return self.avoidingStateMachineCoW { newState in
+                let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
+                newState = .bothQuiescing(state)
+                newState.closeIfNeeded(state)
+                return result
+            }
 
         case .quiescingPrefaceSent(var state):
-            let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
-            self.state = .quiescingPrefaceSent(state)
-            return result
+            return self.avoidingStateMachineCoW { newState in
+                let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
+                newState = .quiescingPrefaceSent(state)
+                return result
+            }
 
         case .idle, .prefaceReceived, .quiescingPrefaceReceived:
             // We're waiting for the preface.
             return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.MissingPreface(), type: .protocolError), effect: nil)
 
         case .fullyQuiesced(var state):
-            // We allow duplicate GOAWAY here, so long as it ratchets downwards.
-            let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
-            self.state = .fullyQuiesced(state)
-            return result
+            return self.avoidingStateMachineCoW { newState in
+                // We allow duplicate GOAWAY here, so long as it ratchets downwards.
+                let result = state.sendGoAwayFrame(lastStreamID: lastStreamID)
+                newState = .fullyQuiesced(state)
+                return result
+            }
+
+        case .modifying:
+            preconditionFailure("Must not be left in modifying state")
         }
     }
 

    }

    /// The state required for a connection that is quiescing due to both peers sending GOAWAY.
    private struct BothQuiescingState: ConnectionStateWithRole, ConnectionStateWithConfiguration, LocallyQuiescingState, RemotelyQuiescingState, MaySendFrames, MayReceiveFrames, HasLocalSettings, HasRemoteSettings, QuiescingState, HasFlowControlWindows {
        let role: ConnectionRole
        var headerBlockValidation: ValidationState
        var contentLengthValidation: ValidationState

        // sent its own. That means we have to be active or quiescing.
        switch self.state {
        case .active(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receiveSettingsAck(frameEncoder: &frameEncoder)
                newState = .active(state)
                return result
            }

        case .locallyQuiesced(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receiveSettingsAck(frameEncoder: &frameEncoder)
                newState = .locallyQuiesced(state)
                return result
            }

        case .remotelyQuiesced(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receiveSettingsAck(frameEncoder: &frameEncoder)
                newState = .remotelyQuiesced(state)
                return result
            }

        case .bothQuiescing(var state):
            return self.avoidingStateMachineCoW { newState in
                let result = state.receiveSettingsAck(frameEncoder: &frameEncoder)
                newState = .bothQuiescing(state)
                return result
            }

        case .idle, .prefaceSent, .prefaceReceived, .quiescingPrefaceReceived, .quiescingPrefaceSent:
            return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.ReceivedBadSettings(), type: .protocolError), effect: nil)

        case .fullyQuiesced:
            return .init(result: .connectionError(underlyingError: NIOHTTP2Errors.IOOnClosedConnection(), type: .protocolError), effect: nil)

        case .modifying:
            preconditionFailure("Must not be left in modifying state")
        }
    }

