{"record":{"id":"f1e069718fb3b5e7","repo":"unknwon/the-way-to-go_ZH_CN","slug":"s-d-d-v","errorCode":null,"errorMessage":"%s:%d:%d: %v","messagePattern":"%s:%d:%d: %v","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"eBook/13.1.md","lineNumber":118,"sourceCode":"\n作为第二个例子考虑用 `json` 包的情况。当 `json.Decode()` 在解析 JSON 文档发生语法错误时，指定返回一个 `SyntaxError` 类型的错误：\n\n```go\ntype SyntaxError struct {\n\tmsg    string // description of error\n// error occurred after reading Offset bytes, from which line and columnnr can be obtained\n\tOffset int64\n}\n\nfunc (e *SyntaxError) Error() string { return e.msg }\n```\n\n在调用代码中你可以像这样用类型断言测试错误是不是上面的类型：\n\n```go\nif serr, ok := err.(*json.SyntaxError); ok {\n\tline, col := findLine(f, serr.Offset)\n\treturn fmt.Errorf(\"%s:%d:%d: %v\", f.Name(), line, col, err)\n}\n```\n\n包也可以用额外的方法 (methods)定义特定的错误，比如 `net.Error`：\n\n```go\npackage net\ntype Error interface {\n\tTimeout() bool   // Is the error a timeout?\n\tTemporary() bool // Is the error temporary?\n}\n```\n\n在 [15.1 节](15.1.md) 我们可以看到怎么使用它。\n\n正如你所看到的一样，所有的例子都遵循同一种命名规范：错误类型以 `...Error` 结尾，错误变量以 `err...` 或 `Err...` 开头或者直接叫 `err` 或 `Err`。\n\n`syscall` 是低阶外部包，用来提供系统基本调用的原始接口。它们返回封装整数类型错误码的 `syscall.Errno`；类型 `syscall.Errno` 实现了 `Error` 接口。","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/unknwon/the-way-to-go_ZH_CN/blob/7a54d34d3657084b6a59e5618bd069b912d571aa/eBook/13.1.md#L100-L136","documentation":"Wrapping pattern from section 13.1: when JSON decoding fails with *json.SyntaxError, the caller type-asserts the error, converts serr.Offset (bytes read before the error) to line and column via a findLine helper, and returns fmt.Errorf(\"%s:%d:%d: %v\", f.Name(), line, col, err) — a file:line:col annotation like a compiler emits. This wrapper error is produced only for syntax-level malformed JSON.","triggerScenarios":"json.Decoder/Unmarshal on malformed JSON: trailing commas, single quotes, unescaped newlines inside strings, truncated streams. The branch fires specifically when err is *json.SyntaxError with a valid Offset; io.ErrUnexpectedEOF or *json.UnmarshalTypeError take other paths. Note findLine is not provided by encoding/json — you must implement it by counting newlines in the first Offset bytes.","commonSituations":"User- or machine-generated config/data files that get truncated (log rotation mid-write, partial downloads); hand-edited JSON with trailing commas; feeds switching to JSONL so extra objects after the first break strict decoding; readers surprised the message points at bytes, not the original line numbering of pretty-printed files.","solutions":["Open the reported file:line:col — the message localizes the first offending byte; fix the JSON there (comma, quote, brace)","Implement findLine if you copy the pattern: scan the first serr.Offset bytes counting '\\n' and the column as the remainder","Validate before processing: dry-run decode, or jq/lint at ingest, so malformed input is rejected at the boundary","If truncation is the cause, fix the writer (atomic temp+rename writes, verified content-length downloads) rather than patching files"],"exampleFix":"// before: bare error, no location\nif err := dec.Decode(&v); err != nil {\n\treturn err // \"invalid character '}' looking for beginning of ...\"\n}\n\n// after: locate the failure for the user\nif serr, ok := err.(*json.SyntaxError); ok {\n\tline, col := findLine(f, serr.Offset)\n\treturn fmt.Errorf(\"%s:%d:%d: %v\", f.Name(), line, col, err)\n}","handlingStrategy":"type-guard","validationCode":"// dry-run decode at the trust boundary before business logic\nif err := json.NewDecoder(bytes.NewReader(raw)).Decode(&v); err != nil {\n\treturn err // reject malformed input on ingest\n}","typeGuard":"func asSyntaxError(err error) (*json.SyntaxError, bool) {\n\tvar serr *json.SyntaxError\n\tif errors.As(err, &serr) {\n\t\treturn serr, true\n\t}\n\treturn nil, false\n}","tryCatchPattern":"if serr, ok := err.(*json.SyntaxError); ok {\n\tline, col := findLine(f, serr.Offset)\n\treturn fmt.Errorf(\"%s:%d:%d: %v\", f.Name(), line, col, err)\n}\nreturn err","preventionTips":["Validate incoming JSON at the trust boundary (dry-run decode) before business logic touches it","Use json.Decoder (not Unmarshal) on streams so byte offsets are meaningful","Fix producers of truncated files: write atomically (temp+rename) and verify content-length on downloads","Always include the original error (%v or %w) when enriching, so the underlying reason survives"],"tags":["go","json","fmt-errorf","error-wrapping","diagnostics"],"backgroundTag":null,"analyzedSha":"7a54d34d3657084b6a59e5618bd069b912d571aa","analyzedAt":"2026-08-15T15:13:06.026Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}