AVExportSession in Xcode16 - "exportAsynchronouslyWithCompletionHandler: more than once."

I’m experiencing a crash at runtime when trying to extract audio from a video. This issue occurs on both iOS 18 and earlier versions. The crash is caused by the following error:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '*** -[AVAssetExportSession exportAsynchronouslyWithCompletionHandler:] Cannot call exportAsynchronouslyWithCompletionHandler: more than once.
(0x1851435ec 0x1826dd244 0x1970c09c0 0x214d8f358 0x214d95899 0x190a1c8b9 0x214d8efd9 0x30204cef5 0x302053ab9 0x190a5ae39)
libc++abi: terminating due to uncaught exception of type NSException

My previous code worked fine, but it's crashing with Swift 6.

Does anyone know a solution for this?

Previous code:

func extractAudioFromVideo(from videoURL: URL, exportHandler: ((AVAssetExportSession, CurrentValueSubject<Float, Never>?) -> Void)? = nil, completion: @escaping (Swift.Result<URL, Error>) -> Void) {
    let asset = AVAsset(url: videoURL)

    
    // Create an AVAssetExportSession to export the audio track
    guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
        completion(.failure(NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to create AVAssetExportSession"])))
        return
    }
    
    // Set the output file type and path
    guard let filename = videoURL.lastPathComponent.components(separatedBy: ["."]).first else { return  }
    let outputURL = VideoUtils.getTempAudioExportUrl(filename)
    VideoUtils.deleteFileIfExists(outputURL.path)
    exportSession.outputFileType = .m4a
    exportSession.outputURL = outputURL
    
    let audioExportProgressPublisher = CurrentValueSubject<Float, Never>(0.0)
    if let exportHandler = exportHandler {
        exportHandler(exportSession, audioExportProgressPublisher)
    }
    
    // Periodically check the progress of the export session
    let timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
        audioExportProgressPublisher.send(exportSession.progress)
    }
    
    // Export the audio track asynchronously
    exportSession.exportAsynchronously {
        switch exportSession.status {
        case .completed:
            completion(.success(outputURL))
        case .failed:
            completion(.failure(exportSession.error ?? NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unknown error occurred while exporting audio"])))
        case .cancelled:
            completion(.failure(NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Export session was cancelled"])))
        default:
            completion(.failure(NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unknown export session status"])))
        }
        
        // Invalidate the timer when the export session completes or is cancelled
        timer.invalidate()
    }
}

## New Code: 


func extractAudioFromVideo(from videoURL: URL, exportHandler: ((AVAssetExportSession, CurrentValueSubject<Float, Never>?) -> Void)? = nil, completion: @escaping (Swift.Result<URL, Error>) -> Void) 
{
	let asset = AVAsset(url: videoURL)
	
	// Create an AVAssetExportSession to export the audio track
	guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
		completion(.failure(NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to create AVAssetExportSession"])))
		return
	}
	
	// Set the output file type and path
	guard let filename = videoURL.lastPathComponent.components(separatedBy: ["."]).first else { return  }
	let outputURL = VideoUtils.getTempAudioExportUrl(filename)
	VideoUtils.deleteFileIfExists(outputURL.path)
	exportSession.outputFileType = .m4a
	exportSession.outputURL = outputURL
	
	let audioExportProgressPublisher = CurrentValueSubject<Float, Never>(0.0)
	if let exportHandler {
		exportHandler(exportSession, audioExportProgressPublisher)
	}
	
	let task = Task {
		if #available(iOS 18.0, *) {
			// Handle export for iOS 18 and later
			let states = exportSession.states(updateInterval: 0.1)
			for await state in states {
				switch state {
				case .pending, .waiting:
					break
				case .exporting(progress: let progress):
					print("Exporting: \(progress.fractionCompleted)")
					if progress.isFinished {
						completion(.success(outputURL))
					} else if progress.isCancelled {
						completion(.failure(NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Export session was cancelled"])))
					} else {
						audioExportProgressPublisher.send(Float(progress.fractionCompleted))
					}
				}
			}
			
			try await exportSession.export(to: outputURL, as: .m4a)  // Only call export once
			
		} else {
			// Handle export for iOS versions below 18
			let publishTimer = Timer.publish(every: 0.1, on: .main, in: .common)
				.autoconnect()
				.sink { [weak exportSession] _ in
					guard let exportSession = exportSession else { return }
					audioExportProgressPublisher.send(exportSession.progress)
				}
			
			// Only call export once
			await exportSession.export()
			
			// Handle the export session's status
			switch exportSession.status {
			case .completed:
				completion(.success(outputURL))
			case .failed:
				completion(.failure(exportSession.error ?? NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unknown error occurred while exporting audio"])))
			case .cancelled:
				completion(.failure(NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Export session was cancelled"])))
			default:
				completion(.failure(NSError(domain: "com.example.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unknown export session status"])))
			}
			
			// Invalidate the timer when the export session completes or is cancelled
			publishTimer.cancel()
		}
	}
	task.cancel()
}
AVExportSession in Xcode16 - "exportAsynchronouslyWithCompletionHandler: more than once."
 
 
Q