Starting with go 1.13, the go.mod proxy server is enabled by default. Part of, or adjacent to, the proxy is also a checksum database. It caches things, and in particular it caches negative results, which may be surprising or frustrating. One option is to avoid it entirely, but should you use the proxy, it has some caveats.

In my case, I tag a new version of a library, then push to my server. Then I edit go.mod in the application to use that tag, and run go build. This attempts to fetch the tag from my server. This frequently fails because there’s a bit of caching involved on the server, and it can take a few minutes to notice the tag. In the past, this was easily resolved by kicking the server, or waiting a minute for things to catch up.

When running go 1.13, however, things are not so simple. Even after my server is refreshed and serving the latest version, the sum.golang.org server will return a 410 Gone response for that tag. This occurs even if you set GOPROXY=direct and skip the proxy.

This happened to me recently, and I was forced to dig into the documentation to figure out what was happening. Alas, while everything is thoroughly documented, it takes a little while to read through it all looking for the relevant info, and nobody likes unscheduled manual reading in the midst of a deploy.

In order to bypass the checksum, you also need to set GOSUMDB=off. Or use get -insecure, or some other means of disabling it. There appear to be many ways to disable or modify how the proxy works.

Per this issue, the cache will last for one hour, which is probably long enough that you don’t want to simply wait it out. Unfortunately, while it’s easy enough to bypass the proxy on a development machine, it may be more difficult to do so in production? If you accidentally misorder your pushes and builds, you may find yourself unable to deploy for some time.

It would be better, of course, to avoid fetching via the proxy before the origin is ready, but mistakes happen. And when they do, there’s no convenient way to unpoison this cache. Burn another tag, I guess.

There’s also the potential for a limited denial of service here. Should somebody guess you’re about to deploy v1.2.3, they can preemptively fetch that version and poison the cache with a 410. Now you finish pushing, but none of your downstream users (who may be using the proxy even if you aren’t) will be able to receive this update until the cache expires.