unknwon/the-way-to-go_ZH_CN · error
%s:%d:%d: %v
Error message
%s:%d:%d: %v
What it means
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.
Source
Thrown at eBook/13.1.md:118
作为第二个例子考虑用 `json` 包的情况。当 `json.Decode()` 在解析 JSON 文档发生语法错误时,指定返回一个 `SyntaxError` 类型的错误:
```go
type SyntaxError struct {
msg string // description of error
// error occurred after reading Offset bytes, from which line and columnnr can be obtained
Offset int64
}
func (e *SyntaxError) Error() string { return e.msg }
```
在调用代码中你可以像这样用类型断言测试错误是不是上面的类型:
```go
if serr, ok := err.(*json.SyntaxError); ok {
line, col := findLine(f, serr.Offset)
return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
}
```
包也可以用额外的方法 (methods)定义特定的错误,比如 `net.Error`:
```go
package net
type Error interface {
Timeout() bool // Is the error a timeout?
Temporary() bool // Is the error temporary?
}
```
在 [15.1 节](15.1.md) 我们可以看到怎么使用它。
正如你所看到的一样,所有的例子都遵循同一种命名规范:错误类型以 `...Error` 结尾,错误变量以 `err...` 或 `Err...` 开头或者直接叫 `err` 或 `Err`。
`syscall` 是低阶外部包,用来提供系统基本调用的原始接口。它们返回封装整数类型错误码的 `syscall.Errno`;类型 `syscall.Errno` 实现了 `Error` 接口。View on GitHub (pinned to 7a54d34d36)
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
Example fix
// before: bare error, no location
if err := dec.Decode(&v); err != nil {
return err // "invalid character '}' looking for beginning of ..."
}
// after: locate the failure for the user
if serr, ok := err.(*json.SyntaxError); ok {
line, col := findLine(f, serr.Offset)
return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
} Defensive patterns
Strategy: type-guard
Validate before calling
// dry-run decode at the trust boundary before business logic
if err := json.NewDecoder(bytes.NewReader(raw)).Decode(&v); err != nil {
return err // reject malformed input on ingest
} Type guard
func asSyntaxError(err error) (*json.SyntaxError, bool) {
var serr *json.SyntaxError
if errors.As(err, &serr) {
return serr, true
}
return nil, false
} Try / catch
if serr, ok := err.(*json.SyntaxError); ok {
line, col := findLine(f, serr.Offset)
return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
}
return err Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- math: square root of negative number %g
- usage: %s infile.txt outfile.txt
- pkg: %v
- stack is empty
- I won't be able to do a sqrt of negative number!
AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15).
Data as JSON: /api/errors/f1e069718fb3b5e7.
Report an issue: GitHub.