Just recently, I was reminded how hard correct error handling is, while using the . Go client for Google Cloud Platform The code I was writing looked like this: Everything seemed fine, except was not created! my-object Inspecting the whole thing a bit closer, it turned out that (line 2) returned an error saying that the client is not authorized. writer.Close() My first reaction was, that or should return that error already. But giving it some more thought, I realized that this isn’t possible, and furthermore, it’s perfectly fine for an I/O object to return an error only when closing it. gcpClient.Bucket(“my-gcp-bucket”).Object(“my-object”).NewWriter(context.TODO()) io.Copy(writer, src) The point is, an I/O object can return an error either (1) while acquiring it, (2) while reading from/writing to it, or (3) while closing it. This is part of the contract. So the often used relies on the that errors returned from can be ignored. This isn’t true in general. Examples being the writer from the example above, or even a simple . defer ioObject.Close() assumption Close() os.File From : https://linux.die.net/man/2/close Not checking the return value of () is a common but nevertheless serious programming error. It is quite possible that errors on a previous operation are first reported at the final (). Not checking the return value when closing the file may lead to silent loss of data. close write (2) close Unfortunately, recommends exactly that: The Go blog — Defer, Panic, and Recover As you can see, none of the errors are handled. Close() Correct Error Handling What would a version of this look like with correct error ? Like this: handling What changed? We removed the calls and replaced them with explicit calls in code paths. Now, when an error happens during (line 13) we return an error, but close the two files before (lines 15–17). We ignore the error from because this either succeeds or it fails, but at that point it might be just a consequence of the previous error that has already happened. After the copying is done, we close the files, but explicitly handle the errors from those calls and do not ignore them. defer Close all Copy Close Is this verbose? Yes, it is! When you handle errors correctly, code becomes verbose. It’s also your lifeline when something in production really goes wrong. Unfortunately, this code has some issues as well: it contains a lot of duplicate lines it’s difficult to get the call logic right Close it won’t close files when a panic happens somewhere Can we do better? The SafeCloser Approach It turns out a little helper, that I call , can help: SafeCloser It’s really just a safe-guard so you want close a multiple times. A lot of implementations are already idempotent, but there is no guarantee. The is that guarantee. Closer Closer SafeCloser How does it work in action? For every you simply create a companion and close your through this . Closer SafeCloser Closer SafeCloser Example for our function: CopyFile Note how I declared a before every block and used in there (lines 6, 7, 13, 14). That same is then used at the bottom (lines 21 and 26) when we explicitly close the files. SafeCloser defer SafeCloser We avoided the duplicate lines and panics are handled correctly. I deliberately did not implement the interface with the to avoid misuse. It is intended to wrap any , pass it around, and be lax about closing them several times. Instead, it’s for this very specific use case, where you handle calls differently depending on if you are in failure mode or in success mode. io.Closer SafeCloser not io.Closer Close Summary Correct error handling is hard. Most often it is not done correctly. A little helper like the from above can help make your error handling correct, while keeping it as simple as possible. SafeCloser If you liked this post, you may also be interested in my follow-up post, “ Correct Error Handling is Hard, Part 2 ". is how hackers start their afternoons. We’re a part of the family. We are now and happy to opportunities. Hacker Noon @AMI accepting submissions discuss advertising & sponsorship To learn more, , , or simply, read our about page like/message us on Facebook tweet/DM @HackerNoon. If you enjoyed this story, we recommend reading our and . Until next time, don’t take the realities of the world for granted! latest tech stories trending tech stories