# iRules style checker

> Paste an iRule and read it against the DevCentral iRules Style Guide: indentation, braces, comments, braced expressions, switch --, event priorities, static:: names and more, plus a real Tcl 8.4 syntax check. Parsed, never run. Local, no network.

- Tool: https://ronutz.com/en/tools/f5-irules-style-checker
- Family: Networking

---

## What it does

Reads an iRule against the DevCentral "iRules Style Guide" (published by JRahm with Jim_Deucker on 2022-12-22), adds two points raised in the guide's comment thread, and runs a real Tcl 8.4 parse over it. The rule is parsed, never executed. Each finding names the rule it comes from, the line, and what to change; flagged lines are marked on a numbered copy of the rule.

## What it checks

- **Editor settings (E1 to E3):** tabs and indents that are not multiples of 4 spaces, lines over 100 columns (a warning past 120), Windows line endings, trailing white space, a missing final line feed, and non-ASCII characters, each named with its code point, its official Unicode name and its column.
- **Numbered rules:** characters that break code (R1), F5's size limit (R2), a lone `{` on its own line or `else` on a new line (R4), end-of-line comments, comments without a space and comments between `switch` patterns (R6), several commands on one line (R7), single-line `if` (R8), state stored as words such as `yes` (R9), F5's `and` / `or` / `not` (R10), `}{` with no space or a keyword glued to its brace (R11), unbraced expressions (R12), variables in expressions without spaces around them (R13) or without braces around the name (R14), `switch` and `table` without `--` (R15), events without a priority (R16), `table` entries without a timeout or lifetime (R17; F5's `table` reference otherwise applies a 180-second timeout and an indefinite lifetime), unprefixed `static::` names (R18), `static::` debug flags (R19), and commented-out code (R20).
- **From the comment thread (D1, D2):** `==` or `!=` with a piece of text, where `eq` or `ne` is meant (D1); `break` or `continue` with no loop around it, `break` in a `switch` arm inside a loop, and `return` in a `switch` arm (D2).
- **Syntax:** an error the Tcl 8.4 parser reports, such as `}{` with no space ("extra characters after close-brace"), means the iRule cannot load at all.

## Characters that hide in code

The guide's first rule is about smart quotes and no-break spaces that a word processor slips in. The checker classifies every non-ASCII character with the Unicode Character Database 18.0.0, so it finds the whole family, not just those two:

- **R1, error:** invisible characters (Unicode's Default_Ignorable_Code_Point list: zero-width spaces and joiners, the byte order mark, the soft hyphen, bidirectional controls), spaces that are not the ASCII space (no-break, em, ideographic and others), and typographic quotes. Tested in tclsh 8.4.6: a no-break space glues two words into one command name, curly quotes do not group words, and a zero-width space after a closing brace stops the rule with "extra characters after close-brace".
- **E3, warning:** dashes that are not the ASCII hyphen-minus. Tcl reads them neither as an option dash nor as a minus sign: a `switch` with an en dash (U+2013) typed where `--` belongs takes the dash as the value, and silently matches nothing.
- **E3, note:** other characters that look like ASCII (fullwidth letters, the ellipsis, Roman numerals), and any other non-ASCII character.

This matters for the guide itself: as published on 2026-10-03, its `RULE_INIT` example has a zero-width space after the closing brace and its debug example has a line holding only one, so copying either verbatim breaks the iRule.

## The size limit

F5 K9204 sets the limit at 65,520 characters; BIG-IP refuses to save or load a longer iRule, with an error that reads "Max string size exceeded" and "max:65520". The guide rounds this to 64 KB. The checker counts characters and the bytes they take as UTF-8, and reports R2 when either passes 65,520.

## From the comment thread

- **D1:** Kai Wilke pointed out that the guide's rule 10 example compares text with `==`, and the authors agreed to add an `eq` / `ne` point. `==` compares as numbers whenever both sides look like numbers: in Tcl 8.4.6, `10 == 012` and `1 == "0x0000001"` are both true. F5's How To Write Fast Rules asks for numbers compared to numbers and strings to strings.
- **D2:** Juergen Mang noted that `switch` arms need no `return` or `break` to stop. A `switch` arm never runs into the next one, `return` leaves the whole event (F5's `return` page), and `break` with no loop around it is an error in Tcl 8.4.6 (checked in a proc body). F5 does not document what TMM does with it in an event body.

## Limits

- Array variables such as `$static::pools($key)` are valid Tcl but the site's Tcl engine does not model them. The checker reads each one as a plain variable, keeps checking the rest of the rule, and says so in a note.
- Some rules cannot be judged from text alone. Whether a line starting with `#` is commented-out code or a comment missing its space is a guess based on the first word, so those findings are notes.
- Rule R3 (break the iRule into functional blocks) is a design choice the checker does not judge. R5 (the 4-space indent carried into nested values such as `switch` arms) is covered by the indentation check. The editor setting about avoiding line continuations is not checked.

## Sources

- [F5 DevCentral: iRules Style Guide, with its comment thread](https://community.f5.com/t/irules-style-guide/71151) (read 2026-10-03)
- [F5 K9204: iRules are limited to 65,520 characters](https://my.f5.com/manage/s/article/K9204) (read 2026-10-03)
- [F5 K15650046: Tcl code injection security exposure](https://my.f5.com/manage/s/article/K15650046) (read 2026-10-03)
- [F5 K57410758: use curly braces to avoid double substitution](https://my.f5.com/manage/s/article/K57410758) (read 2026-10-03)
- [F5 iRules reference: How To Write Fast Rules](https://clouddocs.f5.com/api/irules/HowToWriteFastRules.html) (read 2026-10-03)
- [F5 iRules reference: return](https://clouddocs.f5.com/api/irules/return.html) (read 2026-10-03)
- [F5 iRules reference: priority](https://clouddocs.f5.com/api/irules/priority.html) (read 2026-10-03)
- [F5 iRules reference: table](https://clouddocs.f5.com/api/irules/table.html) (read 2026-10-03)
- [Tcl 8.4 manual: switch](https://www.tcl-lang.org/man/tcl8.4/TclCmd/switch.htm) (read 2026-10-03)
- [Tcl 8.4 manual: break](https://www.tcl-lang.org/man/tcl8.4/TclCmd/break.htm) (read 2026-10-03)
- [Unicode Character Database 18.0.0: PropList.txt](https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt) (read 2026-10-03)
- [Unicode Character Database 18.0.0: DerivedCoreProperties.txt](https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt) (read 2026-10-03)
- [Unicode Character Database 18.0.0: UnicodeData.txt](https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt) (read 2026-10-03)

## Standards and references

- [F5 DevCentral: iRules Style Guide (JRahm with Jim_Deucker, 2022-12-22)](https://community.f5.com/t/irules-style-guide/71151) - the editor settings and the numbered rules R1 to R20 the checker reads an iRule against; its comment thread (Kai Wilke on == against eq for text, D1; Juergen Mang on return and break in switch arms, D2)
- [F5 K15650046: Tcl code injection security exposure](https://my.f5.com/manage/s/article/K15650046) - always brace expressions; always put -- before the switch string; the bad option error a value starting with - produces
- [F5 K57410758: warning [use curly braces to avoid double substitution]](https://my.f5.com/manage/s/article/K57410758) - expr, if and while substitute an unbraced argument a second time; the validator warning and the braced fix
- [F5 iRules reference: priority](https://clouddocs.f5.com/api/irules/priority.html) - event priority runs from 0 to 1000, defaults to 500, and lower numbers run first
- [F5 iRules reference: table](https://clouddocs.f5.com/api/irules/table.html) - a table entry gets a default timeout of 180 seconds and an indefinite lifetime when none is given (the R17 finding)
- [F5 iRules reference: How To Write Fast Rules](https://clouddocs.f5.com/api/irules/HowToWriteFastRules.html) - switch over if, chained elseif over separate ifs, switch over matchclass up to 100 elements, braced expr (about a factor of 20), and comparing numbers to numbers and strings to strings, including == against eq (D1)
- [F5 K9204: iRules are limited to 65,520 characters](https://my.f5.com/manage/s/article/K9204) - the 65,520-character limit, and the errors BIG-IP reports when saving or loading a longer iRule (the R2 finding)
- [F5 iRules reference: return](https://clouddocs.f5.com/api/irules/return.html) - return causes immediate exit from the currently executing event (D2); its example writes if{ with no space, which Tcl 8.4.6 runs as a command named if{ (R11)
- [Tcl 8.4 manual: break](https://www.tcl-lang.org/man/tcl8.4/TclCmd/break.htm) - break aborts out to the innermost containing loop command; switch is not one (D2)
- [Tcl 8.4 manual: continue](https://www.tcl-lang.org/man/tcl8.4/TclCmd/continue.htm) - continue goes to the next iteration of the innermost containing loop (D2)
- [Tcl 8.4 manual: switch](https://www.tcl-lang.org/man/tcl8.4/TclCmd/switch.htm) - the -exact, -glob, -regexp and -- options, a body of - shared with the next pattern, default, and comments only inside bodies
- [F5 K6091: The version of Tcl used to develop iRules](https://my.f5.com/manage/s/article/K6091) - the iRules command set was developed from Tcl base version 8.4.6, which is used in all BIG-IP versions; the engine models that version
- [Tcl 8.4.6 source code, tag core-8-4-6 on GitHub](https://github.com/tcltk/tcl/tree/core-8-4-6) - the reference interpreter: the engine was differential-tested against tclsh built from this tag (commit bf3eeadc)
- [Unicode Character Database 18.0.0: UnicodeData.txt](https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt) - character names and compatibility decompositions
- [Unicode Character Database 18.0.0: PropList.txt](https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt) - the White_Space, Quotation_Mark and Dash properties
- [Unicode Character Database 18.0.0: DerivedCoreProperties.txt](https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt) - the Default_Ignorable_Code_Point property

## Related reading

- [ASCII: the 128 codes, and why the table is laid out that way](https://ronutz.com/en/learn/ascii-the-128-codes.md): Seven bits, eight columns, sixteen rows: how the ASCII table is organised, why upper and lower case are one bit apart, what the 33 controls were defined for and which of them still do something, why white space depends on who is asking, and the HTML references that look like ASCII and are not.
- [Building strings in iRules: quotes, braces, append, concat and lists](https://ronutz.com/en/learn/irules-building-strings.md): Quotes substitute, braces do not, and brackets run a command: almost every surprise when an iRule builds a value comes from those three rules. Here is what Tcl does to each word before a command sees it, how append, concat and lappend differ, why a value with spaces is a list, and how double substitution lets data run as code.
- [Expect scripts, read slowly: spawn, expect, send and the mistakes between them](https://ronutz.com/en/learn/expect-scripts-explained.md): Expect has driven interactive programs since 1990 with four verbs: spawn starts one, expect waits for its output, send types at it, interact hands it to you. Network engineers still write it to log in to a box and read one answer back. The manual page is short and precise, and nearly every script that misbehaves breaks one of its sentences: the 10-second default timeout, the implicit null action, the pattern that flushes the buffer, the return character, the connection closed on exit. Here are those sentences, with what each one costs when ignored.
- [Hidden and lookalike characters: what a line of text can hide](https://ronutz.com/en/learn/hidden-and-lookalike-characters.md): Zero-width characters, bidirectional controls that reorder what you see (Trojan Source), line breaks your parser does not see, Cyrillic letters that pass for Latin, and the typographic quotes and dashes that break configs: what each one does, how the Unicode security documents describe it, and how to find them.
- [iRules LX, explained: what runs where when Tcl calls Node.js](https://ronutz.com/en/learn/irules-lx-explained.md): iRules LX puts a Node.js process beside the Traffic Management Microkernel and lets a Tcl iRule call into it with ILX::call, wait at most three seconds by default, and get the answer back as a Tcl value. This is the whole mechanism, object by object and command by command, from F5's own reference: workspaces, extensions, plugins and the LX rule; ILX::init, ILX::call and ILX::notify; dedicated and single process modes; npm without an internet connection; the Node.js 6.9.1 runtime that BIG-IP 21.1 still ships after removing 0.12; the upgrade that used to break workspaces; and the questions to ask before a design depends on it.
- [The DevCentral iRules Style Guide, rule by rule, with the reasons](https://ronutz.com/en/learn/irules-style-guide-explained.md): F5's DevCentral published an iRules Style Guide in 2022: editor settings and twenty numbered rules. Some are taste, but several prevent real failures: an iRule that will not load, a switch an attacker can steer, an expression that runs request data as code, a log storm. Here are the rules grouped by what they protect, with the reason behind each, what the comment thread under the guide corrected, and what has changed since it was written.
- [Zero or one: where BIG-IP starts counting](https://ronutz.com/en/learn/bigip-zero-or-one.md): Tcl counts from 0, several commands F5 adds count from 1, counters return 1 for the first item, many zeros in the configuration are values rather than positions, and the same path segment is element 1, field 2 or index 1 depending on who is asking. Here is where each one comes from, in F5's own words, with the traps and the places where F5's pages disagree with themselves.
