I have a Tauri/Rust application with a native Swift File Provider extension. Both are configured to use the same App Group, but the extension cannot access the shared continer at all - it can't even list contents or create files. Getting "Operation not permitted" despite all configurations appearing correct. The Rust side manages the database (used on Windows/Linux/macOS), while the File Provider extension needs read access to display files in Finder.
Architecture:
- Main app: Tauri/Rust creates SQLite database
- Extension: Swift File Provider needs read access
- Communication: App Groups shared container
- Rust -> Swift via
@_cdeclFFI to get container path
Current Configuration:
- Same Team ID (UF927XXXXX) for both
- Same App Group (group.com.domain.files)
- Both sandboxed with identical entitlements
- File permissions: -rw-rw-rw- (no ACL)
- Code signing valid
- Paths identical: /Users/user/Library/Group Containers/group.com.domain.files/files.sqlite
The Problem:
Extension loads but cannot access container - fails on all operations with "Operation not permitted". The extension can't even list the container contents.
What I've Verified:
- ✅ Entitlements match
- ✅ Team IDs match
- ✅ App Groups identical
- ✅ Sandbox enabled for both
- ✅ Code signing valid
- ✅ File exists with correct permissions
Both Entitlements have this content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.domain.files</string>
</array>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>
Swift Plugin - Get Container Path (called from Rust):
@_cdecl("swift_get_app_group_path")
public func getAppGroupPath() -> UnsafePointer<CChar>? {
guard let containerURL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.domain.files"
) else {
return nil
}
return UnsafePointer(strdup(containerURL.path))
}
Swift Extension - Debug Access (showing failures):
func testContainerAccess() {
guard let container = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.domain.files"
) else {
print("❌ Cannot get container URL")
return
}
print("📍 Container path: \(container.path)")
// Test 1: List contents
do {
let contents = try FileManager.default.contentsOfDirectory(atPath: container.path)
print("✅ Can list container: \(contents)")
} catch {
print("❌ Cannot list container: \(error)")
}
// Test 2: Check if DB file exists
let dbURL = container.appendingPathComponent("files.sqlite")
if FileManager.default.fileExists(atPath: dbURL.path) {
print("✅ DB file exists")
} else {
print("❌ DB file missing")
}
// Test 3: Try to read DB file
do {
let data = try Data(contentsOf: dbURL)
print("✅ Can read DB file, size: \(data.count)")
} catch {
print("❌ Cannot read DB file: \(error)")
}
// Test 4: Try SQLite open
var db: OpaquePointer?
if sqlite3_open_v2(dbURL.path, &db, SQLITE_OPEN_READONLY, nil) == SQLITE_OK {
print("✅ SQLite can open database")
sqlite3_close(db)
} else {
let error = String(cString: sqlite3_errmsg(db))
print("❌ SQLite open failed: \(error)")
sqlite3_close(db)
}
}
Swift Extension - Info.plist (File Provider config):
<key>NSExtension</key>
<dict>
<key>NSExtensionFileProviderDocumentGroup</key>
<string>group.com.domain.files</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.fileprovider-nonui</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).FileProviderExtension</string>
</dict>
Environment:
- macOS Tahoe (26.0)
- Local signing (no Apple Developer account)
- Xcode
1 Answer 1
TL;DR
If your extension can't access app groups: Go to extension target → Signing & Capabilities → Remove App Groups capability → Re-add it → Add your app group ID again. Properly configured app groups show checkboxes, broken ones don't.
After weeks of debugging, I discovered the issue was with how Xcode configures app groups for extensions. This was an incredibly frustrating to track down.
I was so stuck that I created an entirely new native macOS app from scratch with the same setup (main app + extension with shared app groups) to isolate whether this was a Rust/Tauri-specific issue. Everything worked fine in the main app, but the exact same error occurred in the extension (the app group was inaccessible).
This proved it wasn't related to my Rust setup at all, but rather something fundamental with Xcode's extension configuration.
I finally noticed something: the app group section looked visually different between the main app and extension:
Main app (where I manually added app groups): Shows "checkboxes" next to app group names
Extension (where Xcode auto-added app groups during target creation): No checkboxes
See the difference in these screenshots:
Before:Auto added app group
After:Custom added app group
When you create an extension via "New > Target...", Xcode automatically adds the App Groups capability, but it's NOT properly configured despite appearing to be there.
Solution:
- In your extension target, go to Signing & Capabilities
- Remove the existing App Groups capability
- Re-add the App Groups capability using the "+" button
- Add your app group identifier again
After doing this, the checkboxes appeared, and everything worked immediately in the native app. I then tried the same fix in my original Rust project, and it worked perfectly.
Xcode adds REGISTER_APP_GROUPS = YES; to the extension target (in project.pbxproj) when properly configured. This flag is missing when the extension is initially created.
It's 2025, and Xcode still has these kinds of silent configuration issues. There's no error message, no warning, just a visual difference (missing checkboxes) that's incredibly easy to miss. The fact that this took weeks to discover when the fix is literally "remove and re-add" is honestly unacceptable from a tooling perspective, specially for new developers.
Comments
Explore related questions
See similar questions with these tags.