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
- Change err.String() to err.Error() — the direct, mechanical fix
- Import google.golang.org/appengine and google.golang.org/appengine/user instead of the old appengine/user paths
- Run go fix ./... on the old tree to batch-apply mechanical renames, then build again
- 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
- Run 'go fix ./...' when importing legacy pre-Go1 codebases
- Build in CI on the toolchain you ship with — err.String() fails at compile time, which is the earliest possible catch
- Prefer google.golang.org/appengine imports; the old appengine/user paths no longer compile
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.