unknwon/the-way-to-go_ZH_CN · error

err.String()

Error message

err.String()

What it means

err.String() in the App Engine handler (20.5) is pre-Go1 API: the old os.Error interface exposed String(), but since Go 1 the error interface has Error() string. On any modern toolchain this line fails to compile with 'err.String undefined (type error has no field or method String)' — the doc snapshot simply predates Go 1.

Source

Thrown at eBook/20.5.md:29

import (
	"appengine"
	"appengine/user"
	"fmt"
	"net/http"
)

func init() {
	http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	u := user.Current(c)
	if u == nil {
		url, err := user.LoginURL(c, r.URL.String())
		if err != nil {
			http.Error(w, err.String(), http.StatusInternalServerError)
			return
		}
		w.Header().Set("Location", url)
		w.WriteHeader(http.StatusFound)
		return
	}
	fmt.Fprintf(w, "Hello, %v!", u)
}
```

通过在浏览器中重新加载页面来测试它。你的应用程序会给你一个链接,当你遵循这个链接时,会把你重定向到适合测试你的应用程序的本地版本的谷歌登录页面。你可以在这个页面中输入任何你喜欢的用户名,你的应用程序将看到一个基于该用户名的假的 `user.User` 值。当你的应用程序在 App Engine 上运行时,用户将被引导到 Google 账户的登录页面,然后在成功登录或创建账户后,会被重定向到你的应用程序。

<u>用户API:</u>

为了访问这个,我们需要导入一些专门针对 GAE 的 Go 包,即一般的 `appengine` 和 `appengine/user`。

在处理程序中,我们首先需要制作一个与当前请求r相关联的Context对象,这在一行中完成: 

View on GitHub (pinned to 7a54d34d36)

Solutions

  1. Change err.String() to err.Error() — the direct, mechanical fix
  2. Import google.golang.org/appengine and google.golang.org/appengine/user instead of the old appengine/user paths
  3. Run go fix ./... on the old tree to batch-apply mechanical renames, then build again
  4. For new work, migrate off classic App Engine (e.g. Cloud Run) — the Go runtime described in the chapter is retired

Example fix

// before
if err != nil {
    http.Error(w, err.String(), http.StatusInternalServerError)
    return
}

// after
if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}
Defensive patterns

Strategy: type-guard

Validate before calling

// fail fast on a modern toolchain: add a build-time check near the handler
var _ = err.Error // compile error 'err.Error undefined' reveals pre-Go1 code immediately
// (the actual compile error on err.String() already flags the line — fix it there)

Type guard

// modern error interface has Error(), not String()
func isModernError(v interface{}) bool {
    _, ok := v.(interface{ Error() string })
    return ok
}

// usage: assert before calling message-producing helpers
if e, ok := err.(error); ok {
    http.Error(w, e.Error(), http.StatusInternalServerError)
}

Prevention

When it happens

Trigger: Building the chapter-20 guestbook app with Go 1.x or later; the same file also breaks on appengine.NewContext/user.Current, which moved to google.golang.org/appengine in the current SDK.

Common situations: Copying legacy App Engine samples into a modern module; the classic AE (goapp) SDK being deprecated; teams migrating to gcloud + google.golang.org/appengine packages.

Related errors


AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15). Data as JSON: /api/errors/8496c34ccb28e1b6. Report an issue: GitHub.