{"record":{"id":"06d0c75787bbe340","repo":"unknwon/the-way-to-go_ZH_CN","slug":"err-string-06d0c7","errorCode":null,"errorMessage":"err.String()","messagePattern":"err\\.String\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"eBook/20.6.md","lineNumber":53,"sourceCode":"`\n\nvar signTemplate = template.Must(template.New(\"sign\").Parse(signTemplateHTML))\n\nfunc init() {\n\thttp.HandleFunc(\"/\", root)\n\thttp.HandleFunc(\"/sign\", sign)\n}\n\nfunc root(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/html\")\n\tfmt.Fprint(w, guestbookForm)\n}\n\nfunc sign(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/html\")\n\terr := signTemplate.Execute(w, r.FormValue(\"content\"))\n\tif err != nil {\n\t\thttp.Error(w, err.String(), http.StatusInternalServerError)\n\t}\n}\n```\n\n## 链接\n\n- [目录](directory.md)\n- 上一节：[使用用户服务和探索其 API](20.5.md)\n- 下一节：[使用数据存储](20.7.md)\n\n","sourceCodeStart":35,"sourceCodeEnd":64,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/20.6.md#L35-L64","documentation":"err.String() invokes a method that does not exist on Go's built-in error interface. This snippet was written against pre-Go 1 (2011) releases, where errors were the os.Error type carrying a String() method; since Go 1.0 (2012) the error interface exposes only Error() string. Any modern gc toolchain rejects the sample at compile time with `err.String undefined (type error has no field or method String)`, so the sign handler in section 20.6 cannot even build.","triggerScenarios":"Compiling the sign handler from eBook/20.6.md: `err := signTemplate.Execute(w, r.FormValue(\"content\"))` returns the built-in error interface, then the error branch calls `http.Error(w, err.String(), http.StatusInternalServerError)`. go build / go vet / gopls on this snippet fails immediately with an undefined-method error.","commonSituations":"Copying code from tutorials or eBooks written before Go 1.0 — this chapter targets the 2011 App Engine SDK (appengine.NewContext, datastore.SecondsToTime, time.Seconds, all likewise removed or changed). Mirrored/vendored course material that was never migrated, and projects resurrecting legacy Google App Engine guestbook samples, all hit this the moment they are compiled with a modern toolchain.","solutions":["Replace err.String() with err.Error() in the http.Error call at eBook/20.6.md:53 — that is the only method the error interface has.","Migrate the sibling pre-Go 1 APIs in the same chapter so the sample compiles: import google.golang.org/appengine/{http, user, datastore}, and update calls like time.Seconds()/datastore.SecondsToTime to time.Now().","Verify with a modern toolchain: gofmt, then go vet / go build on the extracted snippet; add a return after http.Error so the handler stops on template failure.","Longer term, generate eBook snippets from real compiled sources and build them in CI so doc code cannot drift from the current Go API."],"exampleFix":"// before\nerr := signTemplate.Execute(w, r.FormValue(\"content\"))\nif err != nil {\n\thttp.Error(w, err.String(), http.StatusInternalServerError)\n}\n// after\nerr := signTemplate.Execute(w, r.FormValue(\"content\"))\nif err != nil {\n\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\treturn\n}","handlingStrategy":"validation","validationCode":"// Fail the docs build if any snippet still uses the pre-Go 1 error API.\n// Run over extracted .go snippets or the markdown source:\nfunc snippetsUseDeadErrorAPI(files []string) error {\n\tfor _, f := range files {\n\t\tb, err := os.ReadFile(f)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif strings.Contains(string(b), \"err.String()\") {\n\t\t\treturn fmt.Errorf(\"%s: err.String() was removed in Go 1; use err.Error()\", f)\n\t\t}\n\t}\n\t// ultimate check: the snippet must actually compile\n\tif out, err := exec.Command(\"go\", \"vet\", \"./...\").CombinedOutput(); err != nil {\n\t\treturn fmt.Errorf(\"snippet does not compile: %s\", out)\n\t}\n\treturn nil\n}","typeGuard":"// stringerError reports whether err still carries the pre-Go 1 String() method.\nfunc stringerError(err error) bool {\n\t_, ok := err.(interface{ String() string })\n\treturn ok\n}","tryCatchPattern":"// Go has no try/catch; check the error inline and format it with Error():\nif err := signTemplate.Execute(w, r.FormValue(\"content\")); err != nil {\n\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\treturn // stop the handler; Execute already wrote partial output\n}","preventionTips":["Treat the error interface as having exactly one method, Error() string; String() belongs to fmt.Stringer and to pre-Go 1 os.Error.","Compile and go vet every code sample before publishing; undefined methods are caught at build time for free.","Extract book snippets into real .go files built by CI so they cannot drift from the current Go release.","When porting old App Engine samples, migrate wholesale to google.golang.org/appengine and Go 1 idioms instead of patching single lines.","Prefer current go.dev documentation over mirrors of 2011 tutorials."],"tags":["go","compile-time","deprecated-api","appengine","html-template","documentation"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}