title: AVAssetExportSession intermittent error 11820 "Cannot Complete Export" Suggestion=Try exporting again
body: <blockquote>
    <p>EXPORT STATUS 4 Error Domain=AVFoundationErrorDomain Code=-11820 "Cannot Complete Export" UserInfo={NSLocalizedDescription=Cannot Complete Export, NSLocalizedRecoverySuggestion=Try exporting again.}</p>
  </blockquote>
  
  <p>I'm experiencing an intermittent error when trying to export an <code>AVMutableComposition</code> containing <code>AVMutableVideoCompositionLayerInstruction</code> (s) and an <code>AVMutableVideoComposition</code> using an <code>AVAssetExportSession</code>.</p>
  
  <p>The objective is to merge an unlimited number of videos and applying transitions between clips using layerInstructions.</p>
  
  <p>P.S. The error is not consistent. It works when attempting to merge 5 clips and 18 clips, but doesn't work when attempting to merge 17 clips. </p>
  
  <p>I've posted my code below. Any help is greatly appreciated.</p>
  
  <p>EDIT: It seems the issue is related to the creation of multiple AVMutableCompositionTrack(s). If more than 15 or 16 are created, the error occurs. However, creating multiple AVMutableCompositionTrack(s), I believe, is necessary to overlap all the videos and create overlapping transitions.</p>
  
  <p>EDIT 2: When shorter videos are selected, more videos are processed before the error occurs. Accordingly, it looks like a memory issue whereby tracks are being deallocated. However, there doesn't seem to be a memory leak based on the memory management tool. </p>
  
  <pre><code>-(void)prepareMutableCompositionForPlayback{
  AVMutableComposition *mutableComposition = [[AVMutableComposition alloc] init];
  AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  mainInstruction.backgroundColor = [[UIColor blackColor] CGColor];
  
  NSMutableArray *instructionsArray = [[NSMutableArray alloc] init];
  
  videoStartTime = kCMTimeZero;
  
  for(int i = 0; i &lt; videoAssetsArray.count; i++){
      AVAsset *videoAsset = [videoAssetsArray objectAtIndex:i];
      CMTime currentVideoDuration = [videoAsset duration];
  
      AVMutableCompositionTrack *videoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
      [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, currentVideoDuration) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:videoStartTime error:nil];
  
      CGSize videoSize = [videoTrack naturalSize];
  
      if([videoAsset tracksWithMediaType:AVMediaTypeAudio].count &gt; 0){
          AVMutableCompositionTrack *audioTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
          [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, currentVideoDuration) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:videoStartTime error:nil];
      }
  
      //INSTRUCTIONS - TRANSITIONS
      AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
  
      int transitionNumber = [[videoTransitionsArray objectAtIndex:i] intValue];
      float transitionDuration = [[videoTransitionsDurationArray objectAtIndex:i] floatValue];
  
      if(i == 0){
          [layerInstruction setOpacityRampFromStartOpacity:1.0 toEndOpacity:0.0 timeRange:CMTimeRangeMake(CMTimeSubtract(currentVideoDuration, CMTimeMakeWithSeconds(transitionDuration, 600)), CMTimeMakeWithSeconds(transitionDuration, 600))];
      }
      else{
          int previousTransitionNumber = [[videoTransitionsArray objectAtIndex:i - 1] intValue];
          float previousTransitionDuration = [[videoTransitionsDurationArray objectAtIndex:i - 1] floatValue];
  
          if(i &lt; videoAssetsArray.count - 1){
              [layerInstruction setOpacityRampFromStartOpacity:1.0 toEndOpacity:1.0 timeRange:CMTimeRangeMake(videoStartTime, CMTimeMakeWithSeconds(previousTransitionDuration, 600))];
  
              [layerInstruction setOpacityRampFromStartOpacity:1.0 toEndOpacity:0.0 timeRange:CMTimeRangeMake(CMTimeAdd(videoStartTime, CMTimeSubtract(currentVideoDuration, CMTimeMakeWithSeconds(transitionDuration, 600))), CMTimeMakeWithSeconds(transitionDuration, 600))];
          }
          else{
              [layerInstruction setOpacityRampFromStartOpacity:1.0 toEndOpacity:1.0 timeRange:CMTimeRangeMake(videoStartTime, CMTimeMakeWithSeconds(previousTransitionDuration, 600))];
          }
      }
  
      [instructionsArray addObject:layerInstruction];
  
      if(i &lt; videoAssetsArray.count - 1){
          //TAKING INTO ACCOUNT THE TRANSITION DURATION TO OVERLAP VIDEOS
          videoStartTime = CMTimeAdd(videoStartTime, CMTimeSubtract(currentVideoDuration, CMTimeMakeWithSeconds(transitionDuration, 600)));
      }
      else{
          //TRANSITION NOT APPLIED TO THE END OF THE LAST CLIP
          videoStartTime = CMTimeAdd(videoStartTime, currentVideoDuration);
      }
  }
  
  mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,videoStartTime);
  mainInstruction.layerInstructions = instructionsArray;
  
  AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
  videoComposition.instructions = [NSArray arrayWithObjects:mainInstruction,nil];
  videoComposition.frameDuration = CMTimeMake(1, 30);
  videoComposition.renderSize = CGSizeMake(1920, 1080);
  
  NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *documentsDirectory = [paths objectAtIndex:0];
  NSString *videoOutputPath = [documentsDirectory stringByAppendingPathComponent:@"videoRecordingFinalOutput.mov"];
  NSURL *videoOutputURL = [[NSURL alloc] initFileURLWithPath:videoOutputPath];
  
  AVAssetExportSession *videoExportSession = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetHighestQuality];
  videoExportSession.outputURL = videoOutputURL;
  videoExportSession.videoComposition = videoComposition;
  videoExportSession.outputFileType = AVFileTypeQuickTimeMovie;
  
  [videoExportSession exportAsynchronouslyWithCompletionHandler:^{
      NSLog(@"EXPORT STATUS %ld %@", (long)videoExportSession.status, videoExportSession.error);
  
      if(videoExportSession.error == NULL){
          NSLog(@"EXPORT SUCCESSFUL");
  
          [library writeVideoAtPathToSavedPhotosAlbum:videoOutputURL
                                      completionBlock:^(NSURL *assetURL, NSError *error) {
                                          if(error) {
  
                                              NSError *error = nil;
                                              if([[NSFileManager defaultManager] fileExistsAtPath:videoOutputPath]){
                                                  [[NSFileManager defaultManager] removeItemAtPath:videoOutputPath error:&amp;error];
                                                  if(error){
                                                      NSLog(@"VIDEO FILE DELETE FAILED");
                                                  }
                                                  else{
                                                      NSLog(@"VIDEO FILE DELETED");
                                                  }
                                              }
                                          }
                                          else{
                                              NSError *error = nil;
                                              if([[NSFileManager defaultManager] fileExistsAtPath:videoOutputPath]){
                                                  [[NSFileManager defaultManager] removeItemAtPath:videoOutputPath error:&amp;error];
                                                  if(error){
                                                      NSLog(@"VIDEO FILE DELETE FAILED");
                                                  }
                                                  else{
                                                      NSLog(@"VIDEO FILE DELETED");
                                                  }
                                              }
                                          }
                                      }];
      }
      else{
          NSError *error = nil;
          if([[NSFileManager defaultManager] fileExistsAtPath:videoOutputPath]){
              [[NSFileManager defaultManager] removeItemAtPath:videoOutputPath error:&amp;error];
              if(error){
                  NSLog(@"VIDEO FILE DELETE FAILED");
              }
              else{
                  NSLog(@"VIDEO FILE DELETED");
              }
          }
      }
  }];
  }
  </code></pre>