diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp
index 8bf3e7bec..5bb0e9133 100644
--- a/src/toolbars/ControlToolBar.cpp
+++ b/src/toolbars/ControlToolBar.cpp
@@ -508,6 +508,7 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
                                    PlayAppearance appearance, /* = PlayOption::Straight */
                                    bool backwards, /* = false */
                                    bool playWhiteSpace /* = false */)
+// STRONG-GUARANTEE (for state of mCutPreviewTracks)
 {
    if (!CanStopAudioStream())
       return -1;
@@ -526,28 +527,29 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
 
    SetPlay(true, appearance);
 
-   if (gAudioIO->IsBusy()) {
-      SetPlay(false);
+   bool success = false;
+   auto cleanup = finally( [&] {
+      if (!success) {
+         SetPlay(false);
+         SetStop(false);
+         SetRecord(false);
+      }
+   } );
+
+   if (gAudioIO->IsBusy())
       return -1;
-   }
 
    const bool cutpreview = appearance == PlayAppearance::CutPreview;
-   if (cutpreview && t0==t1) {
-      SetPlay(false);
+   if (cutpreview && t0==t1)
       return -1; /* msmeyer: makes no sense */
-   }
 
    AudacityProject *p = GetActiveProject();
-   if (!p) {
-      SetPlay(false);
+   if (!p)
       return -1;  // Should never happen, but...
-   }
 
    TrackList *t = p->GetTracks();
-   if (!t) {
-      mPlay->PopUp();
+   if (!t)
       return -1;  // Should never happen, but...
-   }
 
    p->mLastPlayMode = mode;
 
@@ -566,10 +568,8 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
 
    double latestEnd = (playWhiteSpace)? t1 : t->GetEndTime();
 
-   if (!hasaudio) {
-      SetPlay(false);
+   if (!hasaudio)
       return -1;  // No need to continue without audio tracks
-   }
 
 #if defined(EXPERIMENTAL_SEEK_BEHIND_CURSOR)
    double init_seek = 0.0;
@@ -620,7 +620,7 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
    }
 
    int token = -1;
-   bool success = false;
+
    if (t1 != t0) {
       if (cutpreview) {
          const double tless = std::min(t0, t1);
@@ -647,13 +647,9 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
 #endif
                tcp0, tcp1, myOptions);
          }
-         else {
+         else
             // Cannot create cut preview tracks, clean up and exit
-            SetPlay(false);
-            SetStop(false);
-            SetRecord(false);
             return -1;
-         }
       }
       else {
          // Lifted the following into AudacityProject::GetDefaultPlayOptions()
@@ -687,12 +683,8 @@ int ControlToolBar::PlayPlayRegion(const SelectedRegion &selectedRegion,
       }
    }
 
-   if (!success) {
-      SetPlay(false);
-      SetStop(false);
-      SetRecord(false);
+   if (!success)
       return -1;
-   }
 
    StartScrollingIfPreferred();
 
@@ -768,8 +760,8 @@ void ControlToolBar::OnPlay(wxCommandEvent & WXUNUSED(evt))
 
    if (p) p->TP_DisplaySelection();
 
+   auto cleanup = finally( [&]{ UpdateStatusBar(p); } );
    PlayDefault();
-   UpdateStatusBar(p);
 }
 
 void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
@@ -861,6 +853,7 @@ void ControlToolBar::Pause()
 }
 
 void ControlToolBar::OnRecord(wxCommandEvent &evt)
+// STRONG-GUARANTEE (for state of current project's tracks)
 {
    if (gAudioIO->IsBusy()) {
       if (!CanStopAudioStream() || 0 == gAudioIO->GetNumCaptureChannels())
@@ -878,14 +871,43 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
 
    SetRecord(true, mRecord->WasShiftDown());
 
+   bool success = false;
+
+   bool shifted = mRecord->WasShiftDown();
+#ifdef EXPERIMENTAL_DA
+   shifted = !shifted;
+#endif
+
+   TrackList *trackList = p->GetTracks();
+   TrackList tracksCopy{};
+   bool tracksCopied = false;
+
+   WaveTrackArray recordingTracks;
+
+   auto cleanup = finally( [&] {
+      if (!success) {
+         if (tracksCopied)
+            // Restore the tracks to remove any inserted silence
+            *trackList = std::move(tracksCopy);
+
+         if ( ! shifted ) {
+            // msmeyer: Delete recently added tracks if opening stream fails
+            for ( auto track : recordingTracks )
+               trackList->Remove(track);
+         }
+
+         SetPlay(false);
+         SetStop(false);
+         SetRecord(false);
+      }
+
+      // Success or not:
+      UpdateStatusBar(GetActiveProject());
+   } );
+
    if (p) {
-      TrackList *trackList = p->GetTracks();
       TrackListIterator it(trackList);
 
-      bool shifted = mRecord->WasShiftDown();
-#ifdef EXPERIMENTAL_DA
-      shifted = !shifted;
-#endif
       bool hasWave = false;
       for (auto t = it.First(); t; t = it.Next()) {
          if (t->GetKind() == Track::Wave) {
@@ -905,7 +927,6 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
 
       /* TODO: set up stereo tracks if that is how the user has set up
        * their preferences, and choose sample format based on prefs */
-      WaveTrackArray newRecordingTracks;
       WaveTrackConstArray playbackTracks;
 #ifdef EXPERIMENTAL_MIDI_OUT
       NoteTrackArray midiTracks;
@@ -928,8 +949,6 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
 
       // If SHIFT key was down, the user wants append to tracks
       int recordingChannels = 0;
-      TrackList tracksCopy{};
-      bool tracksCopied = false;
 
       if (shifted) {
          recordingChannels = gPrefs->Read(wxT("/AudioIO/RecordChannels"), 2);
@@ -975,10 +994,15 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
                t1 = wt->GetEndTime();
                if (t1 < t0) {
                   if (!tracksCopied) {
+                     // Duplicate all tracks before modifying any of them.
+                     // The duplicates are used to restore state in case
+                     // of failure.
                      tracksCopied = true;
                      tracksCopy = *trackList;
                   }
 
+                  // Pad the recording track with silence, up to the
+                  // maximum time.
                   auto newTrack = p->GetTrackFactory()->NewWaveTrack();
                   newTrack->InsertSilence(0.0, t0 - t1);
                   newTrack->Flush();
@@ -987,9 +1011,9 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
                   wxASSERT(bResult); // TO DO: Actually handle this.
                   wxUnusedVar(bResult);
                }
-               newRecordingTracks.push_back(wt);
+               recordingTracks.push_back(wt);
                // Don't record more channels than configured recording pref.
-               if( (int)newRecordingTracks.size() >= recordingChannels ){
+               if( (int)recordingTracks.size() >= recordingChannels ){
                   break;
                }
             }
@@ -1076,7 +1100,7 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
             }
 
             // Let the list hold the track, and keep a pointer to it
-            newRecordingTracks.push_back(
+            recordingTracks.push_back(
                static_cast<WaveTrack*>(
                   trackList->Add(
                      std::move(newTrack))));
@@ -1090,13 +1114,13 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
 
       AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
       int token = gAudioIO->StartStream(playbackTracks,
-                                        newRecordingTracks,
+                                        recordingTracks,
 #ifdef EXPERIMENTAL_MIDI_OUT
                                         midiTracks,
 #endif
                                         t0, t1, options);
 
-      bool success = (token != 0);
+      success = (token != 0);
 
       if (success) {
          p->SetAudioIOToken(token);
@@ -1105,28 +1129,11 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
          StartScrollingIfPreferred();
       }
       else {
-         if (shifted) {
-            // Restore the tracks to remove any inserted silence
-            if (tracksCopied)
-               *trackList = std::move(tracksCopy);
-         }
-         else {
-            // msmeyer: Delete recently added tracks if opening stream fails
-            for (unsigned int i = 0; i < newRecordingTracks.size(); i++) {
-               trackList->Remove(newRecordingTracks[i]);
-            }
-         }
-
          // msmeyer: Show error message if stream could not be opened
          wxMessageBox(_("Error opening sound device. Try changing the audio host, recording device and the project sample rate."),
                       _("Error"), wxOK | wxICON_EXCLAMATION, this);
-
-         SetPlay(false);
-         SetStop(false);
-         SetRecord(false);
       }
    }
-   UpdateStatusBar(GetActiveProject());
 }
 
 
@@ -1187,6 +1194,8 @@ void ControlToolBar::OnFF(wxCommandEvent & WXUNUSED(evt))
 
 void ControlToolBar::SetupCutPreviewTracks(double WXUNUSED(playStart), double cutStart,
                                            double cutEnd, double  WXUNUSED(playEnd))
+
+// STRONG-GUARANTEE (for state of mCutPreviewTracks)
 {
    ClearCutPreviewTracks();
    AudacityProject *p = GetActiveProject();
@@ -1207,6 +1216,7 @@ void ControlToolBar::SetupCutPreviewTracks(double WXUNUSED(playStart), double cu
       if (track1)
       {
          // Duplicate and change tracks
+         // Clear has a very small chance of throwing
          auto new1 = track1->Duplicate();
          new1->Clear(cutStart, cutEnd);
          decltype(new1) new2{};
@@ -1216,6 +1226,8 @@ void ControlToolBar::SetupCutPreviewTracks(double WXUNUSED(playStart), double cu
             new2->Clear(cutStart, cutEnd);
          }
 
+         // use NOTHROW-GUARANTEE:
+
          mCutPreviewTracks = std::make_unique<TrackList>();
          mCutPreviewTracks->Add(std::move(new1));
          if (track2)
diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp
index 04d59df1c..eab3a30b4 100644
--- a/src/widgets/Ruler.cpp
+++ b/src/widgets/Ruler.cpp
@@ -2672,19 +2672,21 @@ void AdornedRulerPanel::HandleQPRelease(wxMouseEvent &evt)
       ClearPlayRegion();
    }
 
-   StartQPPlay(evt.ShiftDown(), evt.ControlDown());
-
    mMouseEventState = mesNone;
    mIsDragging = false;
    mLeftDownClick = -1;
 
-   if (mPlayRegionLock) {
-      // Restore Locked Play region
-      SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd);
-      mProject->OnLockPlayRegion();
-      // and release local lock
-      mPlayRegionLock = false;
-   }
+   auto cleanup = finally( [&] {
+      if (mPlayRegionLock) {
+         // Restore Locked Play region
+         SetPlayRegion(mOldPlayRegionStart, mOldPlayRegionEnd);
+         mProject->OnLockPlayRegion();
+         // and release local lock
+         mPlayRegionLock = false;
+      }
+   } );
+
+   StartQPPlay(evt.ShiftDown(), evt.ControlDown());
 }
 
 void AdornedRulerPanel::StartQPPlay(bool looped, bool cutPreview)
@@ -2732,18 +2734,20 @@ void AdornedRulerPanel::StartQPPlay(bool looped, bool cutPreview)
          options.timeTrack = NULL;
 
       ControlToolBar::PlayAppearance appearance =
-      cutPreview ? ControlToolBar::PlayAppearance::CutPreview
-      : options.playLooped ? ControlToolBar::PlayAppearance::Looped
-      : ControlToolBar::PlayAppearance::Straight;
+         cutPreview ? ControlToolBar::PlayAppearance::CutPreview
+         : options.playLooped ? ControlToolBar::PlayAppearance::Looped
+         : ControlToolBar::PlayAppearance::Straight;
+
+      mPlayRegionStart = start;
+      mPlayRegionEnd = end;
+      Refresh();
+
       ctb->PlayPlayRegion((SelectedRegion(start, end)),
                           options, PlayMode::normalPlay,
                           appearance,
                           false,
                           true);
 
-      mPlayRegionStart = start;
-      mPlayRegionEnd = end;
-      Refresh();
    }
 }