unknwon/the-way-to-go_ZH_CN · error
stack is empty
Error message
stack is empty
What it means
Error returned by Top() in the Chapter 11 generic stack exercise (Stack is a []interface{}). Top() is the non-destructive peek: it returns the last element, and when len(stack) == 0 there is nothing to peek, so instead of indexing into an empty slice it returns (nil, this error). The package teaches the idiomatic Go pattern of returning (value, error) from container accessors rather than panicking.
Source
Thrown at eBook/exercises/chapter_11/stack/stack_general.go:26
func (stack Stack) Len() int {
return len(stack)
}
func (stack Stack) Cap() int {
return cap(stack)
}
func (stack Stack) IsEmpty() bool {
return len(stack) == 0
}
func (stack *Stack) Push(e interface{}) {
*stack = append(*stack, e)
}
func (stack Stack) Top() (interface{}, error) {
if len(stack) == 0 {
return nil, errors.New("stack is empty")
}
return stack[len(stack)-1], nil
}
func (stack *Stack) Pop() (interface{}, error) {
stk := *stack // dereference to a local variable stk
if len(stk) == 0 {
return nil, errors.New("stack is empty")
}
top := stk[len(stk)-1]
*stack = stk[:len(stk)-1] // shrink the stack
return top, nil
}
View on GitHub (pinned to 7a54d34d36)
Solutions
- Call stack.IsEmpty() (value receiver, len(stack)==0) before Top() and skip or report empty input when true
- Always take both return values: if v, err := s.Top(); err != nil { /* empty */ } else { use v }
- If it fires inside a loop, re-check the invariant: the number of Top() calls must never exceed the number of live Push() calls (every Top should correspond to a previously unmatched Push)
- Restructure the caller so Top() only runs in a branch that just successfully Push()ed, guaranteeing non-emptiness
Example fix
// before
val := s.Top() // error ignored; val is nil on empty stack
// after
val, err := s.Top()
if err != nil {
return fmt.Errorf("nothing to read: %v", err)
}
_ = val Defensive patterns
Strategy: validation
Validate before calling
if s.IsEmpty() {
return nil // caller-level: nothing to peek
}
v, err := s.Top()
if err != nil {
return err
} Try / catch
v, err := s.Top()
if err != nil {
// stack is empty: skip, report, or terminate this branch
return err
}
// use v Prevention
- Bind and check both return values of every Top() call; never assume a preceding Push guarantees state across refactors
- Check IsEmpty() at loop boundaries where input can end before the algorithm expects
- Do not bypass Top() by indexing the exported slice type directly — that skips the emptiness guard and panics
- If callers need errors.Is classification, wrap the stack with your own exported ErrEmptyStack; the exercise defines no exported error variable
When it happens
Trigger: Calling Top() on a zero-length Stack: a freshly declared stack (var s Stack), one that was never Pushed, or one fully drained because each Pop() shrinks the slice with *stack = stk[:len(stk)-1].
Common situations: Delimiter-matching or expression-evaluation algorithms that peek assuming an opening item remains; loops that read one element past end of input; reusing a stack field across requests without re-checking emptiness; assuming Top() returns zero quietly instead of an error.
Related errors
- I won't be able to do a sqrt of negative number!
- math - square root of negative number
- Not found error
- things aren’t good
- expected GET
AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15).
Data as JSON: /api/errors/eb6084741ffd6c3e.
Report an issue: GitHub.