diff --git a/moto/s3/exceptions.py b/moto/s3/exceptions.py
index 1ae6900aa..aec003f0e 100644
--- a/moto/s3/exceptions.py
+++ b/moto/s3/exceptions.py
@@ -26,6 +26,10 @@ ERROR_WITH_RANGE = """{% extends 'single_error' %}
{{ range_requested }}{% endblock %}
"""
+ERROR_WITH_STORAGE_CLASS = """{% extends 'single_error' %}
+{% block extra %}{{ storage_class }}{% endblock %}
+"""
+
class S3ClientError(RESTError):
# S3 API uses as the XML tag in response messages
@@ -501,6 +505,20 @@ class InvalidContinuationToken(S3ClientError):
)
+class InvalidObjectState(BucketError):
+ code = 400
+
+ def __init__(self, storage_class, **kwargs):
+ kwargs.setdefault("template", "storage_error")
+ self.templates["storage_error"] = ERROR_WITH_STORAGE_CLASS
+ super(BucketError, self).__init__(
+ error_type="InvalidObjectState",
+ message="The operation is not valid for the object's storage class",
+ storage_class=storage_class,
+ **kwargs,
+ )
+
+
class LockNotEnabled(S3ClientError):
code = 400
diff --git a/moto/s3/responses.py b/moto/s3/responses.py
index d47273655..7dc682758 100644
--- a/moto/s3/responses.py
+++ b/moto/s3/responses.py
@@ -46,6 +46,7 @@ from .exceptions import (
IllegalLocationConstraintException,
InvalidNotificationARN,
InvalidNotificationEvent,
+ InvalidObjectState,
ObjectNotInActiveTierError,
NoSystemTags,
PreconditionFailed,
@@ -1356,6 +1357,8 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
elif key is None:
raise MissingVersion()
+ if key.storage_class == "GLACIER":
+ raise InvalidObjectState(storage_class="GLACIER")
if if_unmodified_since:
if_unmodified_since = str_to_rfc_1123_datetime(if_unmodified_since)
if key.last_modified > if_unmodified_since:
diff --git a/tests/test_s3/test_s3_storageclass.py b/tests/test_s3/test_s3_storageclass.py
index 10e6ff7d8..8eac2e0d2 100644
--- a/tests/test_s3/test_s3_storageclass.py
+++ b/tests/test_s3/test_s3_storageclass.py
@@ -247,3 +247,22 @@ def test_s3_copy_object_for_deep_archive_storage_class_restored():
s3.head_object(Bucket="Bucket2", Key="Second_Object").should.not_have.property(
"Restore"
)
+
+
+@mock_s3
+def test_s3_get_object_from_glacier():
+ s3 = boto3.client("s3", region_name="us-east-1")
+ bucket_name = "tests3getobjectfromglacier"
+ s3.create_bucket(Bucket=bucket_name)
+
+ s3.put_object(
+ Bucket=bucket_name, Key="test.txt", Body="contents", StorageClass="GLACIER"
+ )
+ with pytest.raises(ClientError) as exc:
+ s3.get_object(Bucket=bucket_name, Key="test.txt")
+ err = exc.value.response["Error"]
+ err["Code"].should.equal("InvalidObjectState")
+ err["Message"].should.equal(
+ "The operation is not valid for the object's storage class"
+ )
+ err["StorageClass"].should.equal("GLACIER")