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.
Crash reports can also be used to get insights. We found a crash happening in our Diagnostics framework related to a lack of space:
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:
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) 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:
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:
We can then use the identifier to detach our disk and we’re back to where we started!
hdiutil detach disk2s1
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.