RealityKit entity.write(to:) generates fatal protection error

My app for framing and arranging pictures from Photos on visionOS allows users to write the arrangements they create to .reality files using RealityKit entity.write(to:) that they then display to customers on their websites. This works perfectly on visionOS 2, but fails with a fatal protection error on visionOS 26 beta 1 and beta 2 when write(to:) attempts to write to its internal cache:

2025-06-29 14:03:04.688 Failed to write reality file Error Domain=RERealityFileWriterErrorDomain Code=10 "Could not create parent folders for file path /var/mobile/Containers/Data/Application/81E1DDC4-331F-425D-919B-3AB87390479A/Library/Caches/com.GeorgePurvis.Photography.FrameItVision/RealityFileBundleZippingTmp_A049685F-C9B2-479B-890D-CF43D13B60E9/41453BC9-26CB-46C5-ADBE-C0A50253EC27." UserInfo={NSLocalizedDescription=Could not create parent folders for file path /var/mobile/Containers/Data/Application/81E1DDC4-331F-425D-919B-3AB87390479A/Library/Caches/com.GeorgePurvis.Photography.FrameItVision/RealityFileBundleZippingTmp_A049685F-C9B2-479B-890D-CF43D13B60E9/41453BC9-26CB-46C5-ADBE-C0A50253EC27.}

Has anyone else encountered this problem? Do you have a workaround? Have you filed a feedback?

ChatGPT analysis of the error and my code reports: Why there is no workaround • entity.write(to:) is a black box — you cannot override where it builds its staging bundle • it always tries to create those random folders itself • you cannot supply a parent or working directory to RealityFileWriter • so if the system fails to create that folder, you cannot patch it

👉 This is why you see a fatal error with no recovery.

See also feedbacks: FB18494954, FB18036627, FB18063766

Hey @z3wind,

I'm having trouble reproducing this issue. I am able to write a file to the temporary directory using the following code:

let originalEntity = Entity()
let tempDirectoryURL = Foundation.FileManager.default.temporaryDirectory
let fileURL = tempDirectoryURL.appendingPathComponent("myscene.reality")
do {
    try await originalEntity.write(to: fileURL)
} catch {
 print("Failed to write reality file to '\(fileURL)', due to: \(error)")
}

Are you able to write a basic entity back to the temporary directory using the above code?

Would you be attach a sample project that I can run that reproduces the issue to FB18036627? That'll help us better understand what's going on. If you're not familiar with preparing a test project, take a look at Creating a test project.

Additionally, after running into the issue can you take a sysdiagnose and attach that to FB18036627? For more information on taking a sysdiagnose, please see Profiles and Logs.

Thanks,
Michael

Hi Michael, Thank you for the quick reply. This is my code on visionOS 26 beta 2 using your path for the temoraaryDirectoryURL:

@MainActor func writeArrangementToTemp() async -> URL? {
    var tempURL: URL? = nil
    if let quickLookArrangement = makeFramedPicturesArrangementEntity(),
       let sceneName = gallerySceneRootEntity?.gallerySceneData?.name {
       let temporaryDirectoryURL = Foundation.FileManager.default.temporaryDirectory
        let fileURL = temporaryDirectoryURL.appendingPathComponent("\(sceneName).reality")
        do {
            _ = FileUtilities.deleteFile(url: fileURL)
            try await quickLookArrangement.write(to: fileURL)
            myLog("Wrote reality file to \(fileURL)")
        } catch {
            myLog("Failed to write reality file \(error)")
        }
        tempURL = fileURL
    }
    return tempURL
}

These are my log file entries

2025-06-30 11:34:14.016 Oops: delete failed Spring 2025.reality error “Spring 2025.reality” couldn’t be removed.

2025-06-30 11:35:51.443 Failed to write reality file Error Domain=RERealityFileWriterErrorDomain Code=10 "Could not create parent folders for file path /var/mobile/Containers/Data/Application/C007D73C-5B2C-4F80-B243-D5C0C337731B/Library/Caches/com.GeorgePurvis.Photography.FrameItVision/RealityFileBundleZippingTmp_E655E7B5-6258-43EA-9C33-FEA2343EA0D8/63E04105-B3E6-483F-918B-53758F8925EA." UserInfo={NSLocalizedDescription=Could not create parent folders for file path /var/mobile/Containers/Data/Application/C007D73C-5B2C-4F80-B243-D5C0C337731B/Library/Caches/com.GeorgePurvis.Photography.FrameItVision/RealityFileBundleZippingTmp_E655E7B5-6258-43EA-9C33-FEA2343EA0D8/63E04105-B3E6-483F-918B-53758F8925EA.}

The deleteFile() failure is expected since the temporary directory has not been used before and is expected to be empty. Commenting out the deleteFile makes no difference. The error message remains the same.

Your test creates a simple null Entity(). Real Entities like mine have children, materials and meshes. When trying to reproduce, please use entities with children, custom meshes and materials. The problem seems to be related to caches that write(to:) needs to create probably for these children, meshes and/or materials.

Hello @z3wind,

I've modified writeArrangementToTemp function to take a real entity and I am still not able to reproduce the error. I've tried calling this with the scene that comes with the default visionOS template which contains children, meshes and materials. Additionally, I am also able to write the appModel.root entity of the GrandCanyonView from the recently released Canyon Crosser sample app.

Can you attach a sample project that I can run that reproduces the issue to FB18036627? That'll help us better understand what's going on. If you're not familiar with preparing a test project, take a look at Creating a test project.

Thanks,
Michael

Hi Michael,

I am encountering an error "Unable to open an immersive space when the app does not support multiple scenes" when I attempt to build a minimal immersive space app strictly in Swift 6.2 without any RealityKit resources. For the example project, please look at FB18515832. Note that the Info.plist is autogenerated by Xcode. I get the same message when it is manually generated.

George

Hey @z3wind,

That is the expected behavior. You need to enable scene support in the project settings, by adding a UIApplicationSceneManifest dictionary and setting the UIApplicationSupportsMultipleScenes value to true (which defaults to false). This process is detailed in Specifying the scenes your app supports.

Alternatively, when creating a new visionOS project select RealityKit as your immersive space renderer and this will be configured for you.

Hope this helps,
Michael

Thank you, Michael. Yes that does identify the problem and I have a working test project (EntityWriteToTest) that has no problem correctly saving with entity.write(to:) with trivial test cases. I am now beginning the lengthy task of construction test entities using the app's custom meshes and materials.

The strange thing in the "FrameIt Vision" app error message to me are:

• that entity.write(to:) is trying to use the file path "/var/mobile/Containers/Data/Application/C007D73C-5B2C-4F80-B243-D5C0C337731B/Library/Caches/com.GeorgePurvis.Photography.FrameItVision/RealityFileBundleZippingTmp_E655E7B5-6258-43EA-9C33-FEA2343EA0D8/63E04105-B3E6-483F-918B-53758F8925EA." that seems like a long path name ending with a '.' [period]

• The problem seems to be generated during the RealityFileBundleZipping stage of creating the .reality file by the write(to:) api

• I'm guessing that materials and perhaps meshes are external to the usda file contained in a .reality file and are being zipped.

I have switched to testing in Simulator Vision Pro (4k) for visionOS 26 beta 2. On the simulator, the app writes .reality files with entity.write(to:) without errors and QuickLook subsequently opens the .reality file displaying it correctly.

When I switch to deploying the exact same code on device, the Vision Pro is errors almost immediately on the call to entity.write(to:) with this error

2025-07-01 16:32:50.187 6 framed pictures in the arrangement 2025-07-01 16:32:50.202 🚫 Failed to write reality file file:///private/var/mobile/Containers/Data/Application/B36B01AB-6223-4A69-A79E-227BF35AAEBA/tmp/Empty%20.reality Error Domain=RERealityFileWriterErrorDomain Code=10 "Could not create parent folders for file path /var/mobile/Containers/Data/Application/B36B01AB-6223-4A69-A79E-227BF35AAEBA/Library/Caches/com.GeorgePurvis.Photography.FrameItVision/RealityFileBundleZippingTmp_D373CAF9-7901-42BC-AD74-EF159279788B/FBE36B9F-AA71-4BEE-805B-83CD7CCB0CD8." UserInfo={NSLocalizedDescription=Could not create parent folders for file path /var/mobile/Containers/Data/Application/B36B01AB-6223-4A69-A79E-227BF35AAEBA/Library/Caches/com.GeorgePurvis.Photography.FrameItVision/RealityFileBundleZippingTmp_D373CAF9-7901-42BC-AD74-EF159279788B/FBE36B9F-AA71-4BEE-805B-83CD7CCB0CD8.}

The visionOS 26 simulator correctly handles the entity.write(to:) suggesting that the meshes, textures, and entity structure being written is both correct and written correctly. On device, visionOS 26 beta 1 and 2 seem to have some changes to file permission or sandboxing that are not present in visionOS 2.5 and visionOS 26 simulator.

It appears that the answer to this issue might be found in the ownership of the Caches files. The following is the output from a scan for files owned by root:

App container root: file:///var/mobile/Containers/Data/Application/A155B86A-E9FA-4566-927A-9AF2B0DC0746/
❌ Could not check /private/var/mobile/Containers/Data/Application/A155B86A-E9FA-4566-927A-9AF2B0DC0746/.com.apple.mobile_container_manager.metadata.plist: The file “.com.apple.mobile_container_manager.metadata.plist” couldn’t be opened because you don’t have permission to view it.
🚨 Root-owned item found: /private/var/mobile/Containers/Data/Application/A155B86A-E9FA-4566-927A-9AF2B0DC0746/Library/Caches/com.GeorgePurvis.Photography.FrameItVision
		      NSFileOwnerAccountID: 0
		      NSFileGroupOwnerAccountName: mobile
		      NSFileReferenceCount: 4
		      NSFileType: NSFileTypeDirectory
		      NSFileExtensionHidden: 0
		      NSFileSystemNumber: 16777226
		      NSFileAppendOnly: 0
		      NSFileGroupOwnerAccountID: 501
		      NSFileOwnerAccountName: root
		      NSFileImmutable: 0
		      NSFileSystemFileNumber: 17595554
		      NSFileSize: 128
		      NSFileModificationDate: 2025-04-28 17:02:47 +0000
		      NSFileCreationDate: 2025-04-28 17:02:40 +0000
		      NSFilePosixPermissions: 493
🚨 Root-owned item found: /private/var/mobile/Containers/Data/Application/A155B86A-E9FA-4566-927A-9AF2B0DC0746/Library/Caches/com.GeorgePurvis.Photography.FrameItVision/com.apple.metalfe
		        NSFileGroupOwnerAccountName: mobile
		        NSFileImmutable: 0
		        NSFileAppendOnly: 0
		        NSFilePosixPermissions: 493
		        NSFileType: NSFileTypeDirectory
		        NSFileSystemNumber: 16777226
		        NSFileGroupOwnerAccountID: 501
		        NSFileExtensionHidden: 0
		        NSFileReferenceCount: 2
		        NSFileSystemFileNumber: 17595555
		        NSFileSize: 96
		        NSFileOwnerAccountID: 0
		        NSFileOwnerAccountName: root
		        NSFileModificationDate: 2025-04-28 17:02:40 +0000
		        NSFileCreationDate: 2025-04-28 17:02:40 +0000
❌ Could not list contents of /private/var/mobile/Containers/Data/Application/A155B86A-E9FA-4566-927A-9AF2B0DC0746/SystemData: The file “SystemData” couldn’t be opened because you don’t have permission to view it.

Could this be the cause of the problem? I am unable to delete the root owned files in my sandbox.

How do directories and files become owned by root? [I certainly cannot do it from standard code.]

Why are these two files owned by root?

This is the ChatGPT code that scanned the app directory tree:

import Foundation

func checkForRootOwnedItems(at url: URL, indent: String = "") {
    do {
        let contents = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
        
        for item in contents {
            do {
                let attributes = try FileManager.default.attributesOfItem(atPath: item.path)
                
                if let ownerID = attributes[.ownerAccountID] as? NSNumber {
                    if ownerID.intValue == 0 {
                        // UID 0 is root
                        print("🚨 Root-owned item found: \(item.path)")
                        for (key, value) in attributes {
                            print("\(indent)  \(key.rawValue): \(value)")
                        }
                    }
                }
                
                var isDir: ObjCBool = false
                if FileManager.default.fileExists(atPath: item.path, isDirectory: &isDir),
                   isDir.boolValue {
                    // attempt to recurse
                    checkForRootOwnedItems(at: item, indent: indent + "  ")
                }
                
            } catch {
                // you couldn't even read this file or folder:
                print("❌ Could not check \(item.path): \(error.localizedDescription)")
            }
        }
        
    } catch {
        // this directory itself couldn't be listed:
        print("❌ Could not list contents of \(url.path): \(error.localizedDescription)")
    }
}

// Usage:
if let rootURL = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first?
    .deletingLastPathComponent()
    .deletingLastPathComponent()
{
    checkForRootOwnedItems(at: rootURL)
}

An interesting coincidence: visionOS 2.5 RC was released April 28, 2025 the same day the root owned directory and file were created.

RealityKit entity.write(to:) generates fatal protection error
 
 
Q