Tcl Part I · Module 1 · Introduction to Tcl
When Tcl Refuses to Run: Reading the Error
A beginner treats an error message as a wall and starts changing things. An engineer treats it as the most specific information available and reads it. The difference is not talent — it is knowing that Tcl's errors have a fixed structure, so that once you can read one you can read all of them, including messages for commands you have never used. This chapter takes that structure apart, works through the two errors you will meet more than any others, and then scales up to reading a call stack across several procedures. By the end you should be able to take an unfamiliar Tcl error and say, without guessing, what broke and where.
Foundation14 min readTclPart IFundamentalsDebuggingErrors
Part I · Module 1 · Chapter 1.9 · When Tcl Refuses to Run: Reading the Error
1. Errors Are the Most Useful Output a Script Produces
It is worth being deliberate about this, because the instinct it replaces is strong.
When a script fails, Tcl tells you what it was unable to do, the exact text of the command it was attempting, and the file and line where that command is. That is more precise than anything you could work out by inspection. The common response — change something plausible and run it again — throws that information away and replaces it with trial and error.
So the skill this chapter teaches is small and specific: read the message, all of it, before touching the file.
2. The Anatomy: Four Parts, Always in This Order
Take a deliberately broken script:
puts "starting"
putz "this will not work"invalid command name "putz"
while executing
"putz "this will not work""
(file "oops.tcl" line 2)Four parts. Every script-mode Tcl error has them, in this order:
| Part | In this example | What it is for |
|---|---|---|
| 1. What went wrong | invalid command name "putz" | The actual problem, named. Read this first. |
2. while executing | — | A label marking the start of the context. |
| 3. The command text | "putz "this will not work"" | The command Tcl was running, exactly as written. |
| 4. Where it is | (file "oops.tcl" line 2) | The file and line to open. |
The useful order to read them in is 1, then 4, then 3: find out what went wrong, go to the line, and compare what Tcl says it ran against what you meant to write.
Note also that starting was printed. Line 1 ran and succeeded before line 2 failed, which is Chapter 1.2 §4 — output is not evidence that a script worked.
3. invalid command name — Tcl Does Not Know That Word
invalid command name "putz"Tcl took the first word of a command, looked it up in its table of commands, and found nothing. Four causes, in the order worth checking:
- A typo.
putzforputs,settforset. Most common by a wide margin. - A command from somewhere else. Chapter 1.3 is the whole treatment: the command may be real but belong to a host application rather than to Tcl. If you copied the line from a script that runs inside some tool, this is the likely answer. Confirm with
info commands <name>. - Something that is not a command in the command position. Chapter 1.8 §9 produced
invalid command name "}"from a stray closing brace — Tcl was expecting a command and found a brace. - A version difference. The command exists in a newer Tcl than the one you are running. Chapter 1.4 §4 covers checking.
Note what this error does not mean: it is not a syntax error, and Tcl is not confused about your file. It read your command perfectly and simply has no such command.
4. can't read "x": no such variable — Nothing Has That Name Yet
The other error you will meet constantly:
puts $totalcan't read "total": no such variable
while executing
"puts $total"
(file "unset.tcl" line 1)Tcl was asked for the value of total and no variable by that name exists. Three causes:
- A typo in the name, or a mismatch in case — Tcl variable names are case-sensitive, so
$Totaland$totalare different variables. - Nothing has assigned it yet. Reading before writing. Common when a line gets moved above the one that sets the value.
- It was set somewhere this code cannot see. Tcl's scope rules mean a variable set outside a procedure is not automatically visible inside it. That is Module 11's subject, and it is the cause that takes longest to recognise — the variable genuinely exists, just not here.
5. Reading a Call Stack
Once your code has procedures, an error carries the whole chain of calls that led to it. This looks intimidating and is actually the most useful form of the message.
Here is a script, with line numbers shown so we can cross-reference:
1 proc inner {} {
2 puts $missing_thing
3 }
4 proc outer {} {
5 inner
6 }
7 puts "about to call outer"
8 outerThe numbers are there so we can point at lines; they are not part of the file. Typed into deep.tcl, those eight lines of Tcl are all there is.
Running it:
about to call outer
can't read "missing_thing": no such variable
while executing
"puts $missing_thing"
(procedure "inner" line 2)
invoked from within
"inner"
(procedure "outer" line 2)
invoked from within
"outer"
(file "deep.tcl" line 8)It is the same four-part anatomy from §2, repeated once per level, joined by invoked from within. Read it as three blocks:
- Block 1 —
puts $missing_thing, at(procedure "inner" line 2). This is where it actually broke. - Block 2 —
inner, at(procedure "outer" line 2). This is what called it. - Block 3 —
outer, at(file "deep.tcl" line 8). This is what started the whole thing.
Two rules make this readable every time:
The first block is where it broke. The last block is what set it off. Each
invoked from withinis one step outward.
So the top of the trace is the most specific, and the bottom is the most contextual. Beginners often read only the bottom line, because it names the file — and the bottom line is the least useful one, since line 8 is innocent.
6. Two Kinds of Failure, Reported Differently
One distinction worth having, because it changes what the line number means.
Errors found while executing a command. Everything above. Tcl knew exactly which command to run, ran it, and the command failed. The line number is the command's line, and earlier commands have already run.
Errors found while working out where a command ends. An unclosed quote or brace is different in kind. Before Tcl can run a command it has to know where the command stops, and an unbalanced quote or brace means it cannot:
puts "starting"
puts "oopsstarting
missing "
while executing
"puts "oops
"
(file "broken.tcl" line 2)The message is shorter — there is no specific command failure to report, just missing ". And notice that starting still printed: Tcl worked through the file command by command and only hit the problem on reaching line 2.
The two unbalanced-delimiter messages are worth recognising on sight:
| Message | Meaning | Where to look |
|---|---|---|
missing " | An unclosed double quote | The reported line, and the one before it |
missing close-brace | An unclosed { | The whole block, counting braces |
missing close-brace: possible unbalanced brace in comment | A brace inside a comment | The comments in the block — see Chapter 1.8 §6 |
The third is the one that sends people looking in the wrong place, which is why Tcl special-cases it.
7. The Same Error at the Interactive Prompt
Chapter 1.5 §4 showed this; it is worth one line here because it can be disorienting. At the % prompt the same two errors appear as:
% putz oops
invalid command name "putz"
% puts $nope
can't read "nope": no such variable
%Part 1 only. No while executing, no command text, no file and line — because you are looking at the command you just typed, and the session continues rather than stopping.
This means the prompt is a poor place to practise reading full error messages, and an excellent place to check quickly whether a single command is valid.
8. A Method
Five steps. Boring, and faster than anything else.
- Read line 1 of the error. What went wrong, in Tcl's words.
- Find the topmost location. The first
(file ...)or(procedure ...)— where it broke, not where it started. - Open that line and compare it with part 3, the command text Tcl quoted. A difference means a grouping problem.
- Check the obvious cause for that error class. Typo for
invalid command name; not-yet-assigned or wrong scope forno such variable; comments forunbalanced brace in comment. - Fix one thing and re-run. One change at a time, so the next message means something.
And the check that closes the loop, from Chapter 1.6 §8:
tclsh check.tcl
echo $?0 means it genuinely succeeded. Any other number means it did not, whatever appeared on screen.
9. What This Chapter Deliberately Leaves Open
You can now read an error. You cannot yet handle one — write code that catches a failure, decides what to do about it, and carries on, or that raises a failure of its own with a message you chose.
That is Module 14's subject: catch, error, return codes, try and finally, and the stack trace Tcl keeps for you in a variable. It is a genuinely large topic and it depends on procedures and variables you have not met yet.
For the rest of Part I, the method in §8 is enough. An error stops the script, tells you where, and you fix it.
10. Exercises
Exercise 1 — the anatomy, on purpose. Write oops.tcl from §2 and run it. Then, without looking back, label the four parts of the output. Check against the table.
Exercise 2 — cause both canonical errors. In separate files, produce invalid command name and no such variable. For each, write down which of the causes in §3 or §4 yours was.
Exercise 3 — build the call stack yourself. Copy deep.tcl from §5 and run it. Confirm you get three blocks. Now add a third procedure between outer and inner and predict how many blocks you will get before running it.
Exercise 4 — read a trace backwards and forwards. Using your output from Exercise 3: which line number would you open first, and which line number is the least useful? Explain why the file line number is the one a beginner reads and the wrong one to start with.
Exercise 5 — the three delimiter errors. Produce missing ", then missing close-brace, then possible unbalanced brace in comment. The third needs Chapter 1.8 §6. For each, note whether any output appeared before the error, and explain why using §6.
Exercise 6 — diagnose without running. A colleague sends you this error and nothing else:
can't read "report_path": no such variable
while executing
"puts $report_path"
(procedure "write_summary" line 4)
invoked from within
"write_summary"
(file "flow.tcl" line 22)Write down: which file and line you would open first, what you would look for there, and the two most likely causes. You have never seen their code, and you should still be able to answer all three.
Exercise 7 — close the loop. Take any script that fails, confirm echo $? reports non-zero, fix it, and confirm it reports 0. This is the habit the whole module has been building toward.
11. Summary
- Errors are the most specific output a failing script produces. Read the message before changing the file.
- Script-mode errors have four parts in a fixed order: what went wrong,
while executing, the command text, and the file and line. Read them 1, 4, 3. - The quoted command text is what Tcl actually ran. If it does not match what you intended, the problem is grouping.
invalid command namemeans Tcl has no such command — usually a typo, otherwise a host application's command, a stray brace, or a version difference. It is not a syntax error.no such variablemeans nothing has that name here — a typo, not yet assigned, or set in a scope this code cannot see.- A call stack is the same anatomy repeated. The first block is where it broke; the last is what started it; each
invoked from withinsteps outward. The file line at the bottom is the least useful. - Unbalanced quotes and braces are a different class, reported more briefly, and earlier commands may already have run.
possible unbalanced brace in commentmeans look at the comments, not the code.- At the
%prompt you get part 1 only, and the session continues. - Exit status closes the loop.
0succeeded; anything else did not.
That completes Module 1. You can find and version an interpreter, tell standalone Tcl from an embedded host, use the prompt and a script file for what each is good for, write and run a file, produce output, comment it correctly, and read a failure well enough to fix it without guessing.
What you do not yet have is the thing that has been quietly behind every quoting decision in this module: the rule by which a line of text becomes a command and its words. That rule is the whole of Module 2, and it is the most valuable thing in Part I.
Where this fits
Part of the Tcl curriculum.
