The classic slice mistake is to forget that append doesn't necessarily return a completely new slice backed by a disjoint piece of memory, especially easy if you've been using a language where variables are immutable by default.
The problem is that it will often accidentally work; if you over-run the backing store, you will get a new piece of memory:
a := make([]int, 1, 1) // a is backed by a one-element-long piece of memory
a[0] = 42
b := append(a, 17) // this must allocate a new piece of memory
c := append(a, 37) // this must also allocate a new piece of memory
// At this point a == [42], b == [42, 17], c == [42, 37]
The problem is when the existing capacity is sufficient: a := make([]int, 1, 10) // a is backed by a ten-element-long piece of memory
a[0] = 42
b := append(a, 17) // no need to allocate: just use the existing memory
c := append(a, 37) // no need to allocate: just (re)use the existing memory
// At this point a == [42], b == [42, 37], c == [42, 37]
// ^^^^^^^^^^^^^