{"record":{"id":"5f6a922ae183f113","repo":"unknwon/the-way-to-go_ZH_CN","slug":"err-string-5f6a92","errorCode":null,"errorMessage":"err.String()","messagePattern":"err\\.String\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"eBook/20.7.md","lineNumber":67,"sourceCode":"var guestbookTemplate = template.Must(template.New(\"book\").Parse(guestbookTemplateHTML))\n\ntype Greeting struct {\n\tAuthor  string\n\tContent string\n\tDate    datastore.Time\n}\n\nfunc init() {\n\thttp.HandleFunc(\"/\", root)\n\thttp.HandleFunc(\"/sign\", sign)\n}\n\nfunc root(w http.ResponseWriter, r *http.Request) {\n\tc := appengine.NewContext(r)\n\tq := datastore.NewQuery(\"Greeting\").Order(\"-Date\").Limit(10)\n\tgreetings := make([]Greeting, 0, 10)\n\tif _, err := q.GetAll(c, &greetings); err != nil {\n\t\thttp.Error(w, err.String(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\tif err := guestbookTemplate.Execute(w, greetings); err != nil {\n\t\thttp.Error(w, err.String(), http.StatusInternalServerError)\n\t}\n}\n\nfunc sign(w http.ResponseWriter, r *http.Request) {\n\tc := appengine.NewContext(r)\n\tg := Greeting{\n\t\tContent: r.FormValue(\"content\"),\n\t\tDate:    datastore.SecondsToTime(time.Seconds()),\n\t}\n\tif u := user.Current(c); u != nil {\n\t\tg.Author = u.String()\n\t}\n\t_, err := datastore.Put(c, datastore.NewIncompleteKey(c, \"Greeting\", nil), &g)\n\tif err != nil {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/20.7.md#L49-L85","documentation":"err.String() references a method removed in Go 1.0 (2012). Pre-Go 1, datastore errors were os.Error values with String(); the modern error interface defines only Error() string. The GetAll error branch of root() therefore fails to compile under any current toolchain with `err.String undefined (type error has no field or method String)`, even though the surrounding datastore query code is otherwise well-formed.","triggerScenarios":"Running go build/vet on the root handler from eBook/20.7.md: `q := datastore.NewQuery(\"Greeting\").Order(\"-Date\").Limit(10)` then `if _, err := q.GetAll(c, &greetings); err != nil` — GetAll returns ([]*datastore.Key, error), and the branch calls err.String(), which does not exist on error. Compilation aborts at line 67.","commonSituations":"Following chapter 20 of this eBook (a Chinese Go book written against the 2011 App Engine SDK). Developers who paste the guestbook query sample into a Go 1+ module, or who restore archived GAE projects, hit this alongside its siblings: time.Seconds(), datastore.SecondsToTime, and u.String() on *user.User all date from the same pre-Go 1 era (some were later re-added as different APIs).","solutions":["Change err.String() to err.Error() in the GetAll error branch at eBook/20.7.md:67.","Update the rest of the snippet to Go 1 + google.golang.org/appengine idioms: fetch the context, keep the query, and use time.Time for Greeting.Date instead of datastore.SecondsToTime(time.Seconds()).","Compile-check the extracted snippet (go vet / go build) to flush out the other pre-Go 1 calls in the same function.","In CI, build every code block from the eBook against the current Go release so stale APIs are flagged before publication."],"exampleFix":"// before\nif _, err := q.GetAll(c, &greetings); err != nil {\n\thttp.Error(w, err.String(), http.StatusInternalServerError)\n\treturn\n}\n// after\nif _, err := q.GetAll(c, &greetings); err != nil {\n\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\treturn\n}","handlingStrategy":"validation","validationCode":"// Before trusting a legacy snippet, compile it — go vet turns\n// `err.String undefined (type error has no field or method String)`\n// into a CI failure instead of a runtime surprise:\nfunc validateSnippet(dir string) error {\n\tcmd := exec.Command(\"go\", \"vet\", \"./...\")\n\tcmd.Dir = dir\n\tif out, err := cmd.CombinedOutput(); err != nil {\n\t\treturn fmt.Errorf(\"guestbook sample does not compile: %s\", out)\n\t}\n\treturn nil\n}","typeGuard":"// narrows whether the value exposes the legacy String() method\nfunc hasLegacyString(err error) bool {\n\t_, ok := err.(interface{ String() string })\n\treturn ok\n}","tryCatchPattern":"// Go's error handling for datastore reads — always err.Error(), always return:\nif _, err := q.GetAll(c, &greetings); err != nil {\n\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\treturn\n}","preventionTips":["Memorize the Go 1 error contract: only Error() string exists on error.","Run go vet/staticcheck (or gopls diagnostics) on snippets; they flag undefined methods instantly.","Build every datastore sample in CI against the current google.golang.org/appengine module.","Never copy query/error-handling blocks from pre-2012 tutorials without compiling them first."],"tags":["go","compile-time","deprecated-api","appengine","datastore","documentation"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}