No space left on device: Testing low storage scenarios

No space left on device is an error message that starts to show up more lately. Over the years, storage has grown from 1GB to 1TB but with technologies like iCloud, we can also see storage stopping at 64GB. On top of that, we’re making more content of higher quality that results in lower storage left for the apps you build.

While building the Collect by WeTransfer app we’ve seen quite some users running into low storage errors. It results in both fatal and non-fatal errors. Reason enough to find a way to test and handle this scenario.

Should I test my app for low storage scenarios?

It totally depends whether you get the no space left on device errors in your app. If your app is only showing remote data from JSON responses you’re probably good. However, if you write data to the disk you’re likely to have a scenario with low storage to support.

That’s quite a lot for something you might think is not that important nowadays.

If your app is downloading data you’re also writing data to disk. This download will likely fail if there’s no data left on the device.

How to check for no space left errors?

Before you start diving into fixing this for your app it’s good to know how big of a problem it actually is.

We’ve started looking into our Firebase logs and search for the NSFileWriteOutOfSpaceError which has error code 640. Within Firebase, these errors are logged under non-fatal errors. This only works if you’ve implemented error logging following their documentation.

The No space left on device error logged in Firebase
The “No space left on device” error logged in Firebase

Crash reports can also be used to get insights. We found a crash happening in our Diagnostics framework related to a lack of space:

A crash log showing the "No space left on device" error
A crash log showing the “No space left on device” error

The non-fatal error combined with the crash had an effect on ~7K users in a period of 7 days. That’s quite a lot for something you might think is not that important nowadays.

Reproducing the “No space left on device” error on the simulator

Once you’ve got the insights it’s time to start fixing the issues. An obvious way to do this would be by finding a test device that already has a low storage. You could also create the scenario yourself by adding a lot of content but that is quite time-consuming.

An easier way is to reproduce this on the simulator by creating a small disk image and using that for your app’s storage.

1. Creating a disk image for your app’s storage

We start by creating a disk image using the hdiutil command in the terminal which uses the DiskImages framework to manipulate disk images. In this case, we’re creating a disk with a total space of 1mb.

hdiutil create -size 1m -fs HFS+ /tmp/app-storage-test.dmg

Looking at the disk it shows us that the size indeed is set to 1mb:

The custom disk created for testing low storage scenarios
The custom disk created for testing low storage scenarios

2. Using the custom disk as your simulator app’s storage

To reproduce a low storage scenario and to get the “No space left on device” error we need to first get the path to the documents directory on the simulator. We can do this by using the following piece of code:

let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print("Documents path: \(documentsPath)")

We can use the open command in the terminal to easily open this folder in Finder. Note that we’re using the documents directory in this scenario but you can use any directory relevant to the scenario you’re testing.

We will then use this path as the mount point of our disk:

hdiutil attach /tmp/app-storage-test.dmg -mountpoint /Users/antoinevanderlee/Library/Developer/CoreSimulator/Devices/4B2F28EF-642C-4ED2-8182-2AFBB38FB9AF/data/Containers/Data/Application/C2540427-D3BD-409F-AD61-0A7BB54C9C66/Documents

This basically wraps the documents directory inside the custom volume. The system will use the disk size as it’s reference size to determine how much space is left.

3. Reproduce the scenario by creating content

Everything is now set up to reproduce the scenario. In our case, we created a lot of logs using the Diagnostics framework that caused the crash. Not long after we’ve got the exact same crash and we could start fixing the issue:

The crash related to storage reproduced in Xcode
The crash related to storage reproduced in Xcode

4. Cleaning up the custom disk

After you’ve reproduced and fixed the issue it’s time to detach the disk and restore original behavior. The detach command will likely fail as the mount point is changed as a result of the simulator that is creating a new app folder for every app launch.

Therefore, we need to get the actual name of the disk by using the diskutil list command:

Listing the disks in the terminal for detaching
Listing the disks in the terminal for detaching

We can then use the identifier to detach our disk and we’re back to where we started!

hdiutil detach disk2s1

Conclusion

That’s it! We’ve reproduced the scenario of having “No space left on device” and we fixed our related crash. Even though it might not be a common scenario in your app, it’s good to investigate how big it actually is.

If you like to learn more tips on debugging, check out the debugging category page. Feel free to contact me or tweet to me on Twitter if you have any additional tips or feedback.

Thanks!