127

I'm seeing the below error from my lambda function when I drop a file.csv into an S3 bucket. The file is not large and I even added a 60 second sleep prior to opening the file for reading, but for some reason the file has the extra ".6CEdFe7C" appended to it. Why is that?

[Errno 30] Read-only file system: u'/file.csv.6CEdFe7C': IOError
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 75, in lambda_handler
s3.download_file(bucket, key, filepath)
File "/var/runtime/boto3/s3/inject.py", line 104, in download_file
extra_args=ExtraArgs, callback=Callback)
File "/var/runtime/boto3/s3/transfer.py", line 670, in download_file
extra_args, callback)
File "/var/runtime/boto3/s3/transfer.py", line 685, in _download_file
self._get_object(bucket, key, filename, extra_args, callback)
File "/var/runtime/boto3/s3/transfer.py", line 709, in _get_object
extra_args, callback)
File "/var/runtime/boto3/s3/transfer.py", line 723, in _do_get_object
with self._osutil.open(filename, 'wb') as f:
File "/var/runtime/boto3/s3/transfer.py", line 332, in open
return open(filename, mode)
IOError: [Errno 30] Read-only file system: u'/file.csv.6CEdFe7C'

Code:

def lambda_handler(event, context):

    s3_response = {}
    counter = 0
    event_records = event.get("Records", [])

    s3_items = []
    for event_record in event_records:
        if "s3" in event_record:
            bucket = event_record["s3"]["bucket"]["name"]
            key = event_record["s3"]["object"]["key"]
            filepath = '/' + key
            print(bucket)
            print(key)
            print(filepath)
            s3.download_file(bucket, key, filepath)

The result of the above is:

mytestbucket
file.csv
/file.csv
[Errno 30] Read-only file system: u'/file.csv.6CEdFe7C'

If the key/file is "file.csv", then why does the s3.download_file method try to download "file.csv.6CEdFe7C"? I'm guessing when the function is triggered, the file is file.csv.xxxxx but by the time it gets to line 75, the file is renamed to file.csv?

GG.
  • 21,083
  • 14
  • 84
  • 130
user1530318
  • 25,507
  • 15
  • 37
  • 48
  • Dump not equal to read ! So your file on temp folder (or in ram) need dump not `self._osutil.open(filename, 'wb') as f:`, only allowed `rb`etc. So need handle source file before processing. – dsgdfg Sep 08 '16 at 07:42
  • @user1530318, would you mind to mark the top answer as correct? It seems all right. – Nikolai K. Apr 28 '18 at 17:52

4 Answers4

355

Only /tmp seems to be writable in AWS Lambda.

Therefore this would work:

filepath = '/tmp/' + key

References:

GG.
  • 21,083
  • 14
  • 84
  • 130
joonas.fi
  • 7,478
  • 2
  • 29
  • 17
  • In my similar situation (writing `File` to user.dir: `/`), but with **JAVA** & a 3.8MB .zip Object, this warning printed right before my ["Read-only"] `SDKClientException` printed (but it was happily resolved after using `/tmp/` Solution instead! Probably because the `S3ObjectInputStream` died as soon as it couldn't get the `/` prior): `WARNING: Not all bytes were read from the S3ObjectInputStream, aborting HTTP connection. This is likely an error and may result in sub-optimal behavior. Request only the bytes you need via a ranged GET or drain the input stream after use.` – cellepo Feb 19 '19 at 17:31
  • Tried the same but givig the error OSError: [Errno 30] Read-only file system: 'tmp/token.json'\n" – Himanshu dua Jan 07 '20 at 09:09
  • This is odd, but writing without '/tmp' worked for me for months. Until today, when it broke. Thanks – Andrey Nov 10 '20 at 12:16
  • Hey, do you know what happens to a file/folder created in /tmp/ after the function ends? Is it permanently deleted? – Dubraven Jun 23 '22 at 08:34
  • @Dubraven no files whatsoever in Lambda are expected to persist. I'm not sure if it's defined how often they're deleted, but you should design with the expectation that after your function call is done, your files are deleted. – joonas.fi Jun 26 '22 at 09:37
  • This worked but for some reason I had to escape the second slash, ie ```filepath = '/tmp//filename.txt' ``` – Martin Bamford Jan 12 '23 at 16:49
22

According to http://boto3.readthedocs.io/en/latest/guide/s3-example-download-file.html

The example shows how to use the first parameter for the cloud name and the second parameter for the local path to be downloaded.

enter image description here

in other hand, the amazaon docs, says enter image description here

Thus, we have 512 MB for create files. Here is my code on lambda aws, it works like charm.

.download_file(Key=nombre_archivo,Filename='/tmp/{}'.format(nuevo_nombre))
Egalicia
  • 683
  • 9
  • 17
  • 1
    cool, that's your code, what about it? If your answer solves the question, please add an explanation **why** it works. If it doesn't, please delete it. – sjaustirni Nov 16 '17 at 07:15
  • Corrected, let me know if I have to set more information – Egalicia Nov 17 '17 at 05:46
  • 5
    Even if it is just an example, please, don't put code in an image. While doing that, please fix the typos in your answer. Overall however, the answer got better. :-D – sjaustirni Nov 17 '17 at 17:28
1

I noticed when I uploaded a code for lambda directly as a zip file I was able to write only to /tmp folder, but when uploaded code from S3 I was able to write to the project root folder too.

0

Also for C# works perfect :

using (var fileStream = File.Create("/tmp/" + fName))
{
   str.Seek(0, SeekOrigin.Begin);
   str.CopyTo(fileStream);
}
Nigrimmist
  • 10,289
  • 4
  • 52
  • 53