Search code examples
amazon-web-servicescachingamazon-cloudfront

CloudFront - Unexpected caching behaviour on error


I am seeing a strange behaviour from CloudFront when my origin throws an error.

My scenario is as follows:

Initial request:

  • Hits CF, nothing in cache
  • CF makes request to origin which returns a response with the following:
    • Status code: 200
    • etag header: "example-etag"
    • cache-control header: public, must-revalidate, max-age=0
    • body: Example body
  • The response received by the client has the following:
    • Status code: 200
    • etag header: "example-etag"
    • cache-control header: public, must-revalidate, max-age=0
    • body: Example body

I then make a change to the origin to ensure it throws an error response as follows:

  • Status code: 500
  • etag header: "a-different-etag"
  • cache-control header: no-store
  • body: Internal server error

When making another request (which sends the header if-none-match: "example-etag") I would expect the following to occur:

  • Hits CF which has the result of the first request in its cache but it has expired and must revalidate with the origin
  • CF makes a request to the origin which returns the above error response
  • The etag for this response is different to the etag for the cached response
  • The error response is relayed to the client but is not stored by CF

What I am actually seeing on the second request:

  • Hits CF which has the result of the first request in its cache but it has expired and must revalidate with the origin
  • CF makes a request to the origin which returns the above error response
  • The client receives the following:
    • Status code: 200
    • if-none-match header: "example-etag"
    • cache-control header: public, must-revalidate, max-age=0
    • x-cache header: RefreshHit from cloudfront
    • body: Example body

Is this expected behaviour and if so how do I get CF to relay the error to the client?


Solution

  • Thanks to Kevin's comment I was able to understand that this actually the expected behaviour.

    The documentation at https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html explains that:

    If the origin is unreachable and minimum TTL is greater than 0, CloudFront serves the object that it got from the origin previously. To avoid this behavior, include the Cache-Control: stale-if-error=0 directive with the object returned from the origin. This causes CloudFront to return an error in response to future requests if the origin is unreachable, rather than returning the object that it got from the origin previously.

    I can confirm that returning stale-if-error=0 in the Cache-Control header works and the error is relayed to the user.