Purpose: to detail some of the places where interacting with Tcl leads one to frustration, confusion, aggrevation, anger, hatred, ... (you get the idea...)
namespace: The concept is good, but the execution is flawed, especially if you're doing anything object-oriented. Which is kind of ironic, given that (AFAIK) namespace were created to support OO, specifically incr Tcl. The implementaiton has C++'s fingerprints all over the syntax. Tcl is many things, but C++ is not one of them. The two don't fit well together.
A problem that I keep running into is that I don't typically use the global scope operator :: for objects at global scope, so there's usually a string inequality between what I'm typing and the value of $self, $this, [self\], whatever the OO system is using. And when I'm doing white-box testing (looking for object names in internal object structures) the names in the structures don't match the names in your code, they've all been explicitly namespaced qualified.
glob: the need to somehow quote the glob {} combination so that one gets the quotes passed on to glob. Use quotation marks (") or braces around the arguments to get them pass the parser.
Regular expressions: a similar problem - the need to quote arguments appropriately so that various regular expression metas make it through the tcl parsing.
Tcl comments: Why can I not place unmatched braces in Tcl comments
Tcl hashes vs arrays: Sometimes people attempt to simulate 2 or more dimensions of arrays using the Tcl associated hashes (aka tcl arrays). The gotcha here is that because the array index is a string, white space is significant.
$ set a1(1,2) abc abc $ puts $a1( 1,2) can't read "a1( 1,2)": no such element in array while evaluating {puts $a1( 1,2)}
Another gotcha here is trying to set arrays with white space:
$ set a1( 1,2) abc wrong # args: should be "set varName ?newValue?" while evaluating {set a1( 1,2) abc}
You need to use quotes if you are putting space into that variable.