Generally speaking, if a function failed to complete a task, its return value should be treated as unreliable. Because errors in go are values, the caller may ignore the error it returns. For exmaple:
foo := myType{
Bar: 123,
Foo: "some string",
}
b, _ := json.Marshal(foo)
I'm ignoring the error because it's a type I've created, and I know it can be marshalled. However, it's considered bad practice either way. All the same, now imagine someone calling your function:
slice, _ := mayError()
And your function, after adding 2 elements to the slice, errors. Returning the partial slice could, and probably will, lead to buggy behaviour further down the line. That makes code hard to debug. On balance, I'd say it's best to return a nil slice and an error in that case. If the code looks like this:
slice, _ := mayError() // returns nil, someErr
// panic
if slice[0] != "" {
}
At least the error shows up immediately, and you'll see any errors returned by mayError
are being ignored. This makes the code way easier to debug/maintain/fix.