Mango Snippets » #8

App Engine: Fixing a Go Panic, Metadata Fetch Failed

The Umbrella engine that powers this website is built using App Engine's Go Standard Environment.

In September 2021, Google Cloud enabled most of the legacy App Engine API on the second-generation App Engine runtimes. This means you could now use newer Go versions even in the standard App Engine. I migrated to Go 1.15 then and it worked smoothly.

Today, I was trying to upgrade the runtime to Go 1.20 since it was made generally available on March 24, 2023. Here is what I did:

  1. Install Go 1.20 locally from https://go.dev/doc/install.
  2. Change runtime: go115 to runtime: go120 in the app.yaml file.
  3. Make sure the app-engine-python and app-engine-go components from the gcloud CLI are up to date: gcloud components install app-engine-go app-engine-python

But running dev_appserver.py results in the following panic (trace simplified) when serving a request:

CRITICAL: panic: Metadata fetch failed for
'instance/attributes/gae_backend_version': Get
"http://metadata/computeMetadata/v1/instance/attributes/gae_backend_version":
dial tcp: lookup metadata: no such host

goroutine 7 [running]:
google.golang.org/appengine/v2/panic(...)
	go/src/runtime/panic.go:884 +0x204
google.golang.org/appengine/v2/internal.mustGetMetadata(...)
	google.golang.org/appengine/v2/internal/metadata.go:34 +0xa8
google.golang.org/appengine/v2/internal.VersionID(...)
	google.golang.org/appengine/v2/internal/identity.go:124 +0xe8
google.golang.org/appengine/v2.VersionID(...)
	google.golang.org/appengine/v2/identity.go:60
mangosite/code/public/common.Handle.func1(...)
	mangoumbrella/public/common/common.go:67 +0x430
net/http.HandlerFunc.ServeHTTP(...)
	go/src/net/http/server.go:2122 +0x38
github.com/gorilla/mux.(*Router).ServeHTTP(...)
	github.com/gorilla/mux@v1.8.0/mux.go:210 +0x19c
net/http.(*ServeMux).ServeHTTP(...)
	go/src/net/http/server.go:2500 +0x140
google.golang.org/appengine/v2/internal.executeRequestSafely(...)
	google.golang.org/appengine/v2/internal/api.go:136 +0x68
google.golang.org/appengine/v2/internal.handleHTTP(...)
	google.golang.org/appengine/v2/internal/api.go:116 +0x374
net/http.HandlerFunc.ServeHTTP(...)
	go/src/net/http/server.go:2122 +0x38
net/http.serverHandler.ServeHTTP(...)
	go/src/net/http/server.go:2936 +0x2d8

Upon investigation, I have the following code in my http handler:

import "google.golang.org/appengine/v2"

func handler(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    _ = appengine.VersionID(c)
}

The panic happens at the appengine.VersionID(c) call as it doesn't work locally. Instead, you could check if it's running locally and use a different code path:

if appengine.IsDevAppServer() {
   // Do something else
} else {
   // This runs in production.
   _ = appengine.VersionID(c)
}

Hope this helps.