As soon as we started programming, we found out to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.
I like reading, trying things out, and making things up, so I've run into all sorts of errors. I also enjoy helping other people, so I've run into all sorts of other people's errors, too. I haven't encountered every single error yet (my printer has never been on fire). But I've hung out in IRC channels where people help other people troubleshoot in real-time, I've read countless mailing list posts in the process of troubleshooting something I'm working on, and I don't mind rolling up my sleeves and getting my hands into the source code. In the process, I've learned some of the techniques for finding out where problems might lurk.
So that's it. That's the magic, really. Learn. Make mistakes. Figure things out. Help other people figure things out. Then, when weird problems come up, you can say, "Hmm. Hang on. Let me poke around... hmm... ah, there it is, the doohickey was kerfluzzled and a quick xyzzy fixed it." Or something like that.
See, all those hours hanging out on mailing lists, #linuxhelp, and #emacs in university are paying off...