Opening FileDocument with URL → should only be called in the main thread

Its document says openDocument can open a document at a specific URL. So I've saved a model as a JSON object with its URL and a bookmark as Data. With its security-scoped bookmark data resolved, I am able to open a document except that the app will crash right after opening a document. Console says

should only be called in the main thread

struct ContentView: View {
    @EnvironmentObject var bookmarkViewModel: BookmarkViewModel
    
    var body: some View {
		VStack {
		
		}
		.onAppear {
			loadBookmarks()
		}
}

extension ContentView {
    func loadBookmarks() {        
        print("1 \(Thread.current)") // NSMainThread
        
        Task {
            for bookmarkItem in bookmarkViewModel.bookmarkItems { // resolving a security-scoped bookmark
                print("2 \(Thread.current)") // NSMainThread
                if let _ = resolveBookmark(bookmarkData: bookmarkItem.bookmarkData) {
                    print("3 \(Thread.current)") // NSMainThread                    
                    do {
                        print("4 \(Thread.current)") // NSMainThread                        
                        try await openDocument(at: bookmarkItem.bookmarkURL)                        
                        print("5 \(Thread.current)") // NSMainThread                        
                    } catch {
                        print("\(error.localizedDescription)")
                    }
                }
            }
        }
    }
}

Well, the application is on the main thread. I've checked every line before and after opening a document with its URL. Call what on the main thread? This is confusing. Thanks.

class BookmarkViewModel: ObservableObject {
    @Published var bookmarkItems: [BookmarkItem] = []
    
    var defaultFileManager: FileManager {
        return FileManager.default
    }
    
    var documentURL: URL? {
        ...
    }
    
    init() {
        fetchBookmarkItems()
    }
    
    func fetchBookmarkItems() {
        bookmarkItems.removeAll()
        
        if let documentURL {
            let bookmarkFolderURL = documentURL.appending(path: "MyApp").appending(path: "Bookmarks")
            do {
                let contents = try defaultFileManager.contentsOfDirectory(atPath: bookmarkFolderURL.path)
                for content in contents {
                    ...
                	let fileURL = bookmarkFolderURL.appending(path: content)
                    let data = try Data(contentsOf: fileURL)
                    let bookmarkItem = try JSONDecoder().decode(BookmarkItem.self, from: data)
                    bookmarkItems.append(bookmarkItem)
                }
            } catch {
                print("Error fetching folder content: \(error.localizedDescription)")
            }
        }
    }
}
struct BookmarkItem: Codable, Hashable {
    let bookmarkURL: URL
    let date: Date
    let bookmarkData: Data
    let open: Bool
}
Answered by Tomato in 840498022

I've upgraded my system to macOS 15.5. The bug has been system.

Try using the .task view modifier and removing the Task {} from the function instead.

Okay. I get it. If I look at openDocument, it's labeled

@Environment @MainActor

That's where the main thread issue comes to surface, I guess.

Try using the .task view modifier and removing the Task {} from the function instead.

Thanks. But that's not really the main issue here.

Accepted Answer

I've upgraded my system to macOS 15.5. The bug has been system.