"Main actor-isolated value of type ... passed as a strongly transferred parameter; later accesses could race" using task groups

Hello all, I am working on a project and have a view model that contains a list of items. These items are immutable (structs) and contain a list of other (immutable–struct) objects. The image describes this better.

Here is my models:

public struct GoogleFont: Hashable, Codable, Identifiable {
    
    public struct Variant: Hashable, Codable, Identifiable {
        public var id: String { name }
        
        public let family: GoogleFont
        public let name: String
        var fileURL: String
        
        var fontData: Data?
        var font: Font?
        
        public func fontWithSize(_ size: CGFloat) -> Font? {
            ...
        }
        
        public init(family: GoogleFont, name: String, fileURL: String) {
            ...
        }
        
        private enum Keys: String, CodingKey {
           ...
        }
        
        public init(from decoder: any Decoder) throws {
           ...
        }
        
        public func encode(to encoder: any Encoder) throws {
            ...
        }
    }
    
    /// The name of the primary variant
    public static let primaryVariantName = "regular"
    
    public var id: String { name }
    public let name: String
    public let category: String
    public var variants: [GoogleFont.Variant] = []
    
    public init(name: String, category: String, variants: [GoogleFont.Variant]) {
        ...
    }
    
    public init(name: String, category: String, variantFilePairs: [[String]]) {
        ...
    }
    
    private enum Keys: String, CodingKey {
        ...
    }
    
    public init(from decoder: any Decoder) throws {
        ...
    }
    
    public func encode(to encoder: any Encoder) throws {
        ...
    }
    
    public func getVariant(named name: String) -> Variant? {
        variants.first { variant in
            variant.name == name
        }
    }
    
    public func primaryVariant() -> Variant? {
        getVariant(named: GoogleFont.primaryVariantName)
    }
    ....
}

And here is some of my GoogleFontManager:

@Observable
public class GoogleFontManager {
    private var apiKey: String
    
    public var selectedFont: GoogleFont?
    public var familySearchTerm = "Sacramento"
    public var categoryFilter = Set(GoogleFontCategory.allCases)
    public var sort: GoogleFontSort = .trending
    
    public var allFonts: [GoogleFont] = []
    
    public init(apiKey: String) {
        ...
    }
    
    /// Loads populates the `allFonts` array with fonts from an API request
    @MainActor
    public func loadFonts() async throws {
        let endpoint = "https://www.googleapis.com/webfonts/v1/webfonts"
        
        var parameters = ["key" : apiKey]
        parameters["sort"] = sort.rawValue
        if !familySearchTerm.isEmpty {
            parameters["family"] = familySearchTerm
        }
        
        let fontsData = try await RequestHelper.getData(endpoint, parameters: parameters)
        var fonts = try GoogleFont.decodeFonts(from: fontsData)
        fonts = filterFonts(fonts)
        
        self.allFonts = fonts
    }
    
    
    /// Filters the `allFonts` array based on the set of filters
    public func filterFonts(_ fonts: [GoogleFont]) -> [GoogleFont] {
        ...
    }
    
    
    /// Populates the `fontData` of each font's primary variant
    @MainActor
    public func loadPrimaryVariantsForAllFonts(size: CGFloat = UIFont.labelFontSize) async throws {
        if allFonts.isEmpty { return }
        
        // create a task group that will get all primary variants at the same time
        try await withThrowingTaskGroup(of: (fontIndex: Int, primaryVariantIndex: Int, fontData: Data).self) { group in
            
            // enter a for loop that adds a task to get primary variant for each font
            for fontIndex in allFonts.indices {
                
                let font = allFonts[fontIndex]
                
                // get primary variant name and index in variants list
                guard let primaryVariant = font.primaryVariant(),
                      let primaryVariantIndex = font.variants.firstIndex(where: {
                          $0 == primaryVariant
                      }) else { break }
                
                let variantURL = font.variants[primaryVariantIndex].fileURL
                group.addTask {
                    // Get the font variant's `fontData`
                    return (fontIndex: fontIndex,
                            primaryVariantIndex: Int(primaryVariantIndex),
                            fontData: try await RequestHelper.getData(variantURL))
                }
                
            }
            
            // Now the tasks have been created run the tasks asynchronousely and set font data for the fonts
            for try await variantDataPair in group {
                allFonts[variantDataPair.fontIndex].variants[variantDataPair.primaryVariantIndex].fontData = variantDataPair.fontData
                allFonts[variantDataPair.fontIndex].variants[variantDataPair.primaryVariantIndex].font = try Font(from: variantDataPair.fontData, size: size)
            }
        }

    }
    

    /// ERRORS HERE \\\
    /// Retrieve all font's variants
    @MainActor
    public func loadAllVariantsForSelectedFont(_ size: CGFloat = UIFont.labelFontSize, alwaysLoad: Bool = false) async throws {
        // Unwrap selected font
        guard let selectedFont = selectedFont else { return }
        
        // Load each variant... in a task group
        try await withThrowingTaskGroup(of: (variantIndex: Int, variantData: Data).self) { group in
            for variantIndex in selectedFont.variants.indices {
                // Access variant
                let variant = selectedFont.variants[variantIndex]
                
                // Make sue it needs to be loaded
                guard alwaysLoad || variant.fontData != nil else { continue }
                
                // Load it async
                group.addTask {
                    return (variantIndex: Int(variantIndex),
                            variantData: try await RequestHelper.getData(variant.fileURL))
                }
            }
            
            // Set data and fonts for the fonts
            for try await variantDataPair in group {
                self.selectedFont?.variants[variantDataPair.variantIndex].fontData = variantDataPair.variantData
                self.selectedFont?.variants[variantDataPair.variantIndex].font = try Font(from: variantDataPair.variantData, size: size)
            }
        }
    }
    
}

The problem



I am getting an error in the line group.addTask { in the loadAllVariantsForSelectedFont function.

The error is Main actor-isolated value of type '() async throws -> (variantIndex: Int, variantData: Data)' passed as a strongly transferred parameter; later accesses could race

I am seriously lost with this, and have no clue on how to fix it, and would so appreciate anybody’s thoughts about why it may be happening. What’s more puzzling is the same error does not happen on the loadPrimaryVariantsForAllFonts function’s group.addTask { line; both methods are pretty much the same.

Thank you so much for reading and your help!