unknwon/the-way-to-go_ZH_CN · error
pkg: %v
Error message
pkg: %v
What it means
Safety net inside Parse in section 13.4: a deferred recover() catches any panic from fields2numbers; if the recovered value already implements error it is used as-is, otherwise it is wrapped as fmt.Errorf("pkg: %v", r) so Parse always returns an error-typed value. This message therefore means: a helper panicked with a non-error value — in this listing the string panic("no words to parse") on empty input. Note that as printed ParseError implements String() (older idiom), not Error(), so even typed panics take the "pkg: %v" wrap.
Source
Thrown at eBook/13.4.md:46
type ParseError struct {
Index int // The index into the space-separated list of words.
Word string // The word that generated the parse error.
Err error // The raw error that precipitated this error, if any.
}
// String returns a human-readable error message.
func (e *ParseError) String() string {
return fmt.Sprintf("pkg parse: error parsing %q as int", e.Word)
}
// Parse parses the space-separated words in in put as integers.
func Parse(input string) (numbers []int, err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("pkg: %v", r)
}
}
}()
fields := strings.Fields(input)
numbers = fields2numbers(fields)
return
}
func fields2numbers(fields []string) (numbers []int) {
if len(fields) == 0 {
panic("no words to parse")
}
for idx, field := range fields {
num, err := strconv.Atoi(field)
if err != nil {
panic(&ParseError{idx, field, err})
}View on GitHub (pinned to 7a54d34d36)
Solutions
- Handle empty input at the source without panicking: if len(fields) == 0 { return nil, errors.New("pkg: no words to parse") } — keep panic/recover for truly exceptional paths
- Panic with error values, not strings: panic(fmt.Errorf(...)) or panic(&ParseError{...}) — and give ParseError an Error() string method so the r.(error) branch preserves its type
- On the caller side, unwrap to classify: var pe *ParseError; if errors.As(err, &pe) { use pe.Word } — the 'pkg: %v' text only carries a string
- Preserve cause when wrapping: fmt.Errorf("pkg: %w", e) in the error branch so errors.Is/As chain through the wrapper
Example fix
// before
panic("no words to parse") // recovered → err = "pkg: no words to parse" (untyped string)
// after
if len(fields) == 0 {
return nil, errors.New("pkg: no words to parse")
}
// and panic only with typed errors:
panic(&ParseError{Index: idx, Word: s, Err: err}) Defensive patterns
Strategy: try-catch
Validate before calling
fields := strings.Fields(input)
if len(fields) == 0 {
return nil, errors.New("pkg: no words to parse") // pre-check: skip the panic path
}
return Parse(input) Try / catch
defer func() {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
err = e
} else {
err = fmt.Errorf("pkg: %v", r)
}
}
}() Prevention
- Reserve panic for programmer errors; expected failures (bad input) should return errors directly
- When you must recover, panic with values implementing error so the type assertion preserves structure
- Wrap recovered errors with %w so errors.As can still find typed causes
- Validate obvious cases (empty input, non-numeric tokens) before the parsing core so the panic path stays exceptional
When it happens
Trigger: Parse("") → fields is empty → fields2numbers panics "no words to parse" (a string) → the r.(error) assertion fails → err becomes 'pkg: no words to parse'. Likewise any panic carrying a non-error value (int, plain string) from deeper helpers; Parse("1 2 three") panics with a *ParseError which is stringified through the same wrap in this version.
Common situations: Converting panic-style internal code to error-returning APIs at a package boundary; batch processors where one bad record must not kill the run; maintainers panicking with strings; debugging why the returned error is an opaque 'pkg: ...' wrapper instead of a typed value that carries Word/Index fields.
Related errors
AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15).
Data as JSON: /api/errors/a19b8fa100912a18.
Report an issue: GitHub.