Go Website Sometimes Returns Stale Data After Updating Records

Hi All,

I am experiencing one specific problem with my Go-based website where an API endpoint sometimes returns an older version of a record even though the record has already been updated successfully in the database. The website is built in Go and uses a server-side API to retrieve the data that is displayed to visitors, and under normal circumstances the endpoint returns the current database values as expected. However, after a record is updated, there are situations where a subsequent request from the website still receives the previous value instead of the newly saved one. The database itself shows the updated information when I inspect it directly, so the problem appears to occur somewhere between the completed database update and the response generated by the Go application. This is intermittent rather than a permanent failure, because the same endpoint can return the updated record correctly after some time or after another request is made. I am trying to understand why the Go application can successfully complete the update while a later request can temporarily produce an older representation of the same data.

The affected endpoint is used by the website to retrieve information dynamically, so the returned response is what the frontend ultimately displays to visitors. The request itself completes normally when the problem occurs and does not produce an HTTP error or an obvious database failure. Instead, the application returns a valid response containing the previous value, which makes the issue more difficult to diagnose than a normal request or connection error. I have checked the database immediately after performing an update and can confirm that the new value has been committed, but the website can still receive the earlier value when it requests the same record. If I repeat the request later, the response may contain the expected updated data without any change to the record itself. Because the endpoint is otherwise functioning normally, I am trying to determine whether the stale response could be caused by application-level caching, an in-memory data structure, a long-lived database connection, or some other part of the Go application’s request-handling path that is retaining an older value.

I have already compared the behavior between records that have recently been updated and records that have not changed, and the issue appears to be specifically noticeable shortly after an update. I have also repeated the same GET request several times and compared the response with the value currently stored in the database. In the cases where the problem occurs, the database contains the new value while the Go endpoint continues returning the old value for a period of time. I have checked the handler responsible for retrieving the record and verified that it is using the expected database query rather than intentionally returning a previously stored response. I have also added basic logging around the update and retrieval operations so I can compare the value being written with the value being returned. This has helped confirm that the behavior is not simply a visual problem in the browser, because the HTTP response itself can contain the older data before the frontend receives it. What I am trying to identify now is why the server-side Go application can produce a stale response even though the underlying database already contains the latest version.

One area I would particularly appreciate advice on is how Go developers normally diagnose unexpected stale data when the database has already been updated. The application does not intentionally need long-term caching for these records, so I want to make sure that I am not accidentally retaining an old object somewhere between requests. For example, if a handler or service layer keeps records in memory, I want to understand the safest way to invalidate that data after an update so that the next request always obtains the current database value. I am also wondering whether there is any possibility that concurrent requests are causing an older read to complete after a newer update, resulting in the older object being returned to the client. The website has multiple users accessing the same endpoint, so I want to make sure that the request lifecycle and shared application state are handled correctly. If there are standard Go debugging techniques for tracing a record from the update transaction through the database query and finally into the HTTP response, I would appreciate recommendations on what should be logged and compared.

The reason I want to solve this at the application level is that simply refreshing the website or waiting for another request is not a reliable solution. Visitors should receive the current record when they request it, particularly because the data can be changed by administrators while the website is running. I would like to determine whether the stale response is caused by something in my Go code rather than making arbitrary changes to the database or frontend. I am especially interested in understanding whether I should inspect shared maps, structs retained by services, middleware, HTTP response caching, database transaction boundaries, or any other server-side state that could survive between requests. If there is a recommended approach for ensuring that a read occurring after a successful update always sees the committed value, I would also like to understand how that should be implemented safely when multiple requests may be processed concurrently. My main goal is to find the underlying reason for the stale response rather than simply adding delays or repeatedly querying until the expected value eventually appears.

Has anyone experienced a Go web application returning an older database value even though the corresponding update has already been committed and the database shows the new value? I would appreciate guidance on how to trace this kind of stale-response behavior through a Go application’s handler, service layer, database query, and HTTP response. I can provide a simplified version of the update handler, retrieval handler, database access code, Go version, and an example showing the old and new values if that would help reproduce the problem. For now, I want to keep the investigation focused on this single issue: a Go website intermittently returns stale record data after the record has already been updated successfully in the database. I would like to understand whether the likely cause is application-side caching or shared state, concurrent request handling, transaction visibility, or another part of the Go request lifecycle, and what the recommended debugging and implementation approach would be to make the endpoint consistently return the current database value.

The answer to these types of questions is almost always client-side caching. Browsers can be aggressive about caching. What kind of headers are you setting on your response? What value are you setting in Cache-Control? And have you used a tool like curl to verify that the HTML coming back actually has the older values?

Never using SPA. Safari may keep old cache for weeks using static MPA. Or what does Go send to the browser and what does the browser show?

Or something in the headers that caches non static data? In Caddy I have this header caching only “assets”. No problems yet. Or it could be a CDN issue?

@static path \*.css \*.js \*.png \*.jpg \*.webp \*.jpeg \*.gif \*.ico \*.svg \*.woff \*.woff2 \*.ttf
header @static Cache-Control "public, max-age=31536000, immutable"

Thanks for sharing your Caddy configuration. I understand that caching static assets for a long period is generally fine when the cache rules are limited to files such as CSS, JavaScript, images, and fonts. In my case, though, the main concern is that the GET API response itself sometimes contains the previous record value, even though the database already has the updated value. I’ll check the response headers to see whether any Cache-Control, ETag, or other caching behavior could be affecting the API endpoint, and compare the actual HTTP response with what the browser displays.

I’m also interested in how to distinguish browser or CDN caching from a stale value generated by the Go application. If the response body from a direct API request already contains the old value, would you recommend checking the CDN and server-side caching layers first, or tracing the database query and record value inside the Go handler before the response is written? That would help me narrow down where the old data is being introduced.

Try to execute your endpoint in a REST client (Postman, Bruno, etc). Make changes to the record in your database client and then re-run your request in the REST Client. if it brings the same data, there is something cached in your backend. If works fine then you have to check browser settings and the like…

Then I should focus on this. Is the query correct? If you use this query outside Go (PgAdmin etc)? Is the REST call correct?

I have experience caching in different places. Sometimes it is Cloudflare (CDN), sometimes in Browser or sometimes even in VS Code (even forgot to save…).

Have you tried to “purge” the CDN cache?

How I would go about debugging this problem:

Add a debug log which prints the query and result each time your code runs. You will have three possible outcomes when you retrieve stale data, eauch one ruling out a lot of causes:

  1. No log printed on stale data: you are receiving a cached response somewhere between the client and middleware. (e.g. browser cache, CDN, proxy, go middleware)
  2. Your log prints stale data: the problem is between your code and the database (e.g. reusing a connection with an uncommitted transaction and thus old database state?)
  3. Your log prints the updated data: very unexpected. (e.g. client reusing the wrong variable in the frontend code, or some racing condition with a global variable or wrong use of context in go)

Keep us posted what you find