{"record":{"id":"8496c34ccb28e1b6","repo":"unknwon/the-way-to-go_ZH_CN","slug":"err-string","errorCode":null,"errorMessage":"err.String()","messagePattern":"err\\.String\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"eBook/20.5.md","lineNumber":29,"sourceCode":"\nimport (\n\t\"appengine\"\n\t\"appengine/user\"\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc init() {\n\thttp.HandleFunc(\"/\", handler)\n}\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n\tc := appengine.NewContext(r)\n\tu := user.Current(c)\n\tif u == nil {\n\t\turl, err := user.LoginURL(c, r.URL.String())\n\t\tif err != nil {\n\t\t\thttp.Error(w, err.String(), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tw.Header().Set(\"Location\", url)\n\t\tw.WriteHeader(http.StatusFound)\n\t\treturn\n\t}\n\tfmt.Fprintf(w, \"Hello, %v!\", u)\n}\n```\n\n通过在浏览器中重新加载页面来测试它。你的应用程序会给你一个链接，当你遵循这个链接时，会把你重定向到适合测试你的应用程序的本地版本的谷歌登录页面。你可以在这个页面中输入任何你喜欢的用户名，你的应用程序将看到一个基于该用户名的假的 `user.User` 值。当你的应用程序在 App Engine 上运行时，用户将被引导到 Google 账户的登录页面，然后在成功登录或创建账户后，会被重定向到你的应用程序。\n\n<u>用户API：</u>\n\n为了访问这个，我们需要导入一些专门针对 GAE 的 Go 包，即一般的 `appengine` 和 `appengine/user`。\n\n在处理程序中，我们首先需要制作一个与当前请求r相关联的Context对象，这在一行中完成： \n","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/20.5.md#L11-L47","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nif err != nil {\n    http.Error(w, err.String(), http.StatusInternalServerError)\n    return\n}\n\n// after\nif err != nil {\n    http.Error(w, err.Error(), http.StatusInternalServerError)\n    return\n}","handlingStrategy":"type-guard","validationCode":"// fail fast on a modern toolchain: add a build-time check near the handler\nvar _ = err.Error // compile error 'err.Error undefined' reveals pre-Go1 code immediately\n// (the actual compile error on err.String() already flags the line — fix it there)","typeGuard":"// modern error interface has Error(), not String()\nfunc isModernError(v interface{}) bool {\n    _, ok := v.(interface{ Error() string })\n    return ok\n}\n\n// usage: assert before calling message-producing helpers\nif e, ok := err.(error); ok {\n    http.Error(w, e.Error(), http.StatusInternalServerError)\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["go","appengine","version-migration","compile-error","legacy-api"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}