diff --git a/moto/s3/exceptions.py b/moto/s3/exceptions.py
index 39047bf44..1587d85b4 100644
--- a/moto/s3/exceptions.py
+++ b/moto/s3/exceptions.py
@@ -5,7 +5,7 @@ ERROR_WITH_BUCKET_NAME = """{% extends 'single_error' %}
"""
ERROR_WITH_KEY_NAME = """{% extends 'single_error' %}
-{% block extra %}{{ key_name }}{% endblock %}
+{% block extra %}{{ key }}{% endblock %}
"""
ERROR_WITH_ARGUMENT = """{% extends 'single_error' %}
@@ -91,9 +91,11 @@ class MissingBucket(BucketError):
class MissingKey(S3ClientError):
code = 404
- def __init__(self, key_name):
+ def __init__(self, **kwargs):
+ kwargs.setdefault("template", "key_error")
+ self.templates["key_error"] = ERROR_WITH_KEY_NAME
super(MissingKey, self).__init__(
- "NoSuchKey", "The specified key does not exist.", Key=key_name
+ "NoSuchKey", "The specified key does not exist.", **kwargs
)
diff --git a/moto/s3/models.py b/moto/s3/models.py
index 44aa2493f..8cf875ae9 100644
--- a/moto/s3/models.py
+++ b/moto/s3/models.py
@@ -1620,7 +1620,7 @@ class S3Backend(BaseBackend):
if key is not None:
key.set_acl(acl)
else:
- raise MissingKey(key_name)
+ raise MissingKey(key=key_name)
def put_object_legal_hold(
self, bucket_name, key_name, version_id, legal_hold_status
@@ -1686,7 +1686,7 @@ class S3Backend(BaseBackend):
def set_key_tags(self, key, tags, key_name=None):
if key is None:
- raise MissingKey(key_name)
+ raise MissingKey(key=key_name)
boto_tags_dict = self.tagger.convert_dict_to_tags_input(tags)
errmsg = self.tagger.validate_tags(boto_tags_dict)
if errmsg:
diff --git a/moto/s3/responses.py b/moto/s3/responses.py
index aaa0427ce..6488a93cb 100644
--- a/moto/s3/responses.py
+++ b/moto/s3/responses.py
@@ -1357,7 +1357,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
key = self.backend.get_object(bucket_name, key_name, version_id=version_id)
if key is None and version_id is None:
- raise MissingKey(key_name)
+ raise MissingKey(key=key_name)
elif key is None:
raise MissingVersion()
@@ -1552,7 +1552,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
src_version_id=src_version_id,
)
else:
- return 404, response_headers, ""
+ raise MissingKey(key=src_key)
new_key = self.backend.get_object(bucket_name, key_name)
mdirective = request.headers.get("x-amz-metadata-directive")
diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py
index c75966ed1..a355b706b 100644
--- a/tests/test_s3/test_s3.py
+++ b/tests/test_s3/test_s3.py
@@ -3319,6 +3319,25 @@ def test_boto3_head_object_with_versioning():
old_head_object["VersionId"].should_not.equal(head_object["VersionId"])
+@mock_s3
+def test_boto3_copy_non_existing_file():
+ s3 = boto3.resource("s3")
+ src = "srcbucket"
+ target = "target"
+ s3.create_bucket(Bucket=src)
+ s3.create_bucket(Bucket=target)
+
+ s3_client = boto3.client("s3")
+ with pytest.raises(ClientError) as exc:
+ s3_client.copy_object(
+ Bucket=target, CopySource={"Bucket": src, "Key": "foofoofoo"}, Key="newkey"
+ )
+ err = exc.value.response["Error"]
+ err["Code"].should.equal("NoSuchKey")
+ err["Message"].should.equal("The specified key does not exist.")
+ err["Key"].should.equal("foofoofoo")
+
+
@mock_s3
def test_boto3_copy_object_with_versioning():
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
@@ -3359,7 +3378,7 @@ def test_boto3_copy_object_with_versioning():
Bucket="blah",
Key="test5",
)
- e.value.response["Error"]["Code"].should.equal("404")
+ e.value.response["Error"]["Code"].should.equal("NoSuchKey")
response = client.create_multipart_upload(Bucket="blah", Key="test4")
upload_id = response["UploadId"]
@@ -4701,6 +4720,7 @@ def test_boto3_put_object_tagging():
{
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
+ "Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
)
@@ -4760,6 +4780,7 @@ def test_boto3_put_object_tagging_on_earliest_version():
{
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
+ "Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
)
@@ -4828,6 +4849,7 @@ def test_boto3_put_object_tagging_on_both_version():
{
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
+ "Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
)