Caution when using Play's TemporaryFile

Written by Andrew Conner · Sep 7, 2015

Play! Framework provides several BodyParsers out of the box to parse common HTTP request bodies. One of them is for file uploads. Since Play can’t reasonably know what you’re doing with the body, they can’t aggressively delete the file after the result is returned. [Their solution]() is to clean up the file when the variable is garbage collected, using Java’s finalize—rarely seen in the Scala world. Since the TemporaryFile is held inside request (request.body: TemporaryFile), this is usually reasonable since request won’t be GCed during the lifecycle of the request.

However, this can bite you when doing asynchronous file operations, such as image resizing then uploading to a CDN. Since your APIs typically deal in real Files (instead of the wrapped TemporaryFile), you may assume you can safely pass request.body.file around. As soon as request goes out of scope (usually, by returning to the client), that File reference can be deleted out from under you. Since it’s garbage collection that triggers this, it probably won’t happen often, and will happen somewhat randomly.

Recently, I ran into this when trying to determine why around 1% of image uploads (which involve resizing to various sizes and uploading to S3) on Kifi were failing. Unfortunately, the file deletion seemed to always happen between two lines that couldn’t have deleted it. After a couple hours, we noticed TemporaryFile’s documented behavior. Sigh.

So, be very careful with TemporaryFile. If you would like Play to manage the File lifecycle, make sure you’re done before request.file can be GCed. If not, make a copy immediately, and then assume responsibility for file management yourself.

I would have preferred that Play immediately delete the file after the Action returns, so at least behavior is consistent.

I value your thoughts and feedback. Reach out by email or Twitter.