Skip to main content

Error codes

Every diagnostic TDC can raise, listed by code. Look one up when a run stops and the message alone isn't enough.

How to read a diagnostic

A diagnostic carries four things. The code is the part that never changes between versions — the wording may improve, but TDC193 stays TDC193:

./run demo.tdc
error[TDC193]: "Naem" is not a declared sequence — it would be printed literally
--> demo.tdc:8:11
|
8 |     <line><data>${{Naem}}</data></line>
|           ^^^^^^^^^^^^^^^^^^^^^^
|
help: did you mean "Name"?
note: Declare it in <env>, or set a different inject= pattern if you really want the text ${{…}} in the output.
  • the code — what went wrong, stable across releases;
  • the place — file, line, and column, with the offending element underlined;
  • help: — a guess at what you meant, when the name is a near miss;
  • note: — what to do about it.

Validation runs before generation, so a config with errors produces no data at all rather than half a file. Almost every diagnostic here is an error and stops the run: if the config asked for something it wouldn't actually get, TDC refuses rather than handing back data that looks right but isn't. The exceptions are twelve warnings that let the run finish: TDC136 (a malformed <map> row is skipped and the valid rows still apply), TDC171 (a pack file whose header puts it at no address), TDC200 (a memory estimate that is large but still fits), TDC216 (an expression that is always true or always false), TDC221 (a <uniq> or <distinct> group with one member, which constrains nothing), TDC231 (a <pool> nothing reads), TDC234 (a pool over 100,000 members), TDC299 (a uniq column past 100,000 rows, whose memory follows the row count — its second meaning, a pool declared out of order, is an error) TDC251 (a percent share that asks for less than one row), TDC272 (a locale that is a fine source of names and ships no month names, so the dates come out English) and TDC284 (a secret= written into the config as a literal — a key travels wherever the config does) and TDC301 (a share list that leaves a declared value at 0%, so it can never be drawn). Each says as much in its row below.

The numbers run roughly in the order a config is checked — structure first, then generators, then everything built on top of them — but a number is an identifier, not a classification. Use the groups below.

Document structure

CodeFires whenFix
TDC001The file has no <tdc> root, or it could not be parsed at all — a syntax error, including a closing tag that names another element (<sequence>…</gen>) or elements nested deeper than 64 levels, which no real config reaches and a generated one doesWrap everything in a single <tdc>…</tdc>, or fix the syntax the message points at. Nothing else is checked until the file parses
TDC002<tdc> has no <block> childAdd the <block> that describes one record's layout
TDC003Both version and v are given on <tdc>Keep one — they're aliases
TDC004The declared document version isn't a valid version numberUse a version this runtime supports, e.g. v="0.1" (a value newer than the runtime raises TDC005)
TDC005The file asks for a version newer than this runtimeUpgrade TDC, or lower the declared version
TDC010A tag other than <env> or <block> sits directly under <tdc>Move it inside one of those two
TDC013A tag is nested somewhere it isn't allowedSee Tags for what may contain what
TDC014A tag that has to hold children is written self-closingWrite <env …></env>, not <env …/> — its children would be silently dropped
TDC015A tag carries an attribute the engine doesn't readThe run stops, because the config asked for something it wouldn't get. Check the spelling — the message suggests the nearest real name
TDC020count isn't a non-negative integercount="1000"
TDC021An inject pattern with no hole, or with more than oneA % is the hole only where it has text on BOTH sides, and a marker has exactly one — inject="[[%]]". None ("%%", "%x", no % at all) and nothing is ever substituted; several ("[%]-[%]") and only the rightmost is read, the others turning into literal % your text does not contain. inject="%{%}%" is legal: only its middle % qualifies

Sequences

CodeFires whenFix
TDC030A tag that requires a name doesn't have oneAdd name="…"
TDC031A sequence name starts with _That prefix is reserved for built-ins
TDC032Two sequences share a nameRename one — references to it would be ambiguous
TDC033A name collides with a built-inPick another one; built-ins always win
TDC034A parent value isn't in Parent.Value formUse the two-part form, e.g. parent="Gender.Male"
TDC035The parent sequence is declared after this oneMove the parent above it — resolution is top-down
TDC214parent= names a compound sequenceA parent is filtered by the value it produced, and a group of fields produces none
TDC036A <sequence> has no <gen> inside itA sequence needs a generator to produce anything
TDC110retired — an unnamed <gen> beside a named one now composes rather than failing
TDC111Two fields of one compound sequence share a nameRename one
TDC129A <sequence> inside a config-level tag produces nothing usable thereSee Sequences

Generators

CodeFires whenFix
TDC040A <gen> has no typeAdd type="…" — see Generators
TDC041The type is unknown, or isn't supported on an inline <gen>Check the spelling; TDC suggests the nearest name
TDC050type="text" without valueGive it the list, e.g. value="a,b,c"
TDC051A percent on a value list has more entries than the list has valuesOne percentage per value, e.g. value="a,b" with percent="70,30"
TDC052A percent entry isn't a non-negative numberEvery filled position has to be a number; an empty position splits what's left equally
TDC053The percent values don't add up to 100Adjust them to total 100, or leave a position empty to absorb the remainder
TDC060type="file" without srcPoint src at the file
TDC061The file can't be readCheck the path — it's relative to the config file — or use --data-path
TDC062column doesn't resolveUse a header name (column="email") or a 1-based index (column="2")
TDC064row is used without columnRow linking needs to know which CSV column to draw from
TDC065type="http" without srcPoint it at the service — src="http://127.0.0.1:5566/gen"
TDC066src isn't an http(s) URLUse http://… or https://…, with a host and a path
TDC067in= names nothing that was declared before itThe value sent with each row has to come from an earlier <sequence>
TDC068on_error is neither fail nor emptyfail (default) stops the run; empty blanks the cell
TDC069timeout isn't a positive number of secondstimeout="30" waits thirty seconds for one answer; omit it for the default of 30
TDC070type="template" without valueGive it the dotted address, e.g. value="person.lastName"
TDC071The template address is unknownCheck the spelling, or install the pack that provides it
TDC072value="date.range" without range, or a type="template" parameter the pack doesn't declareAdd range="…", or check the parameter name — the message lists the ones the pack accepts
TDC073A legacy range isn't two valid datesUse YYYY.MM.DD - YYYY.MM.DD
TDC081A number range is malformedvalue="10..99"
TDC082first_zero isn't true or falseThose are the only two values
TDC083length isn't a count, a range, or a comma-separated liste.g. length="8", length="6..9", length="4,6,8"
TDC084A percent on a numeric value has more entries than the range allowsOne percentage per value
TDC085A percent entry on a number isn't a non-negative numberEvery filled position has to be a number
TDC086The percent values on a number don't add up to 100Adjust them to total 100
TDC087include/exclude without a numeric range in valueThey filter a range, so there has to be one
TDC088distribution is combined with an attribute it rules outA named distribution shapes the draw on its own
TDC089The distribution parameters are wrongSee Distributions
TDC090An attribute that has to be a number isn't oneCheck the value
TDC095type="regex" without valueThe pattern goes in value
TDC096regex_max_length isn't a positive integere.g. regex_max_length="64"
TDC097The regex doesn't parseFix the pattern — the parser's own message follows
TDC098type="symbol" is given both value and alphabet, or neitherGive exactly one: an inline set in value, or a named alphabet
TDC099The named alphabet is unknownSee Symbol
TDC128type="advanced_regex" without valueThe pattern goes in value
TDC128(second meaning) default= or if= written on a <case>A <mix> picks its case by percentage and a <switch> by the is key — neither asks a condition. For condition-driven values use a <sequence> with <gen if="…"> branches
TDC130The advanced pattern doesn't parseSee Advanced regex
TDC244type="pattern" with no points, src or upperA drawing needs a shape to read: points="0,0 1,5 2,3", a file in src, or upper/lower for a band

Expressions in if

CodeFires whenFix
TDC100The expression doesn't parseSee Output & formatting
TDC101A binary operator isn't supportedSupported: == != === !== < > <= >= && || + - * /
TDC102A unary operator isn't supportedSupported: !, -, +
TDC103The expression uses computed member accessOnly plain names are allowed
TDC215A name in an if= that no sequence hasIt reads as its own text: alone the branch always fires, compared it never does
TDC216(warning) a branch that can never fire: if="Seq.Value" or if="Seq == Value" naming a value the sequence never produces, <case is="…"> or a <map> key outside the subject's list, parent="Seq.Value" on a value that never occursThe branch is dead. A warning, not an error: a list narrowed on purpose is a real thing to write
TDC217A template path exists, but not for the run's localeThe message names the locale; set local= on the <gen> or <env>, or pick a path your locale ships
TDC218uniq="true" on a sequence with no values of its own — <compute> reads other sequences, if= picks a branch per row, and running/stat/formula/a date offset are computed rather than drawnPut uniq= on the sequences it reads, or wrap them in <uniq>
TDC219A <compute> and a <gen> in the same <sequence> — one of them would be droppedMove the <compute> into its own <sequence> and read the drawn one with <field>
TDC220uniq="true" on a composed value joining two or more drawn partsThe parts have no fixed width, so a unique set of parts is not a unique string: 9+15 and 91+5 are the same three characters. Keep one drawn part, or make the widths fixed
TDC221(warning) A <uniq> or <distinct> around fewer than two <sequence>sA group constrains its members against each other, so one member constrains nothing. Add a second member, or write uniq="true" on the sequence itself

<pool>

See Coherent records.

CodeFires whenFix
TDC222A <pool> with no name, or with no countA pool is read by name and holds a fixed number of members: <pool name="Doctors" count="30">
TDC223A <pool count="…"> that is not a whole number of at least 1A pool of nothing has no member to hand out
TDC224<gen type="pool" value="X"> where no <pool name="X"> is declaredThe message lists the declared pools. Declare it in the same <env>
TDC225filter="field == X" where the two sides can never hold a common valueBoth lists are written in the config, and they do not meet — so every row is narrowed to no member at all. The message names both. Only a certain contradiction is reported here; a value that merely comes up rarely is refused at the row that draws it
TDC226filter= reads Pool.field and the pool has no such fieldThe message lists the pool's fields. An unqualified unknown name is left alone — the expression language reads a bare word as a literal
TDC229${{Ref}} where Ref draws a whole memberA member is a record, not a value. Read a field: ${{Ref.lastName}}
TDC230A <block>, a fixture tag, or another <pool> inside a <pool>A pool is a table other columns read, not something written to a file, and pools do not nest
TDC231(warning) A <pool> no <gen type="pool"> readsIt is built in full before the first row and kept in memory for the whole run, so an unread one is paid for and thrown away. Read it, or remove it
TDC232A name in filter= that is both a field of the pool and a sequenceRename one of them. Qualifying one side does not help — the other name still reads as the member's field, so the test compares a value with itself
TDC234(warning) Over 100,000 membersA pool stays in memory for the whole run — about 320 bytes a member with four fields. If you meant the number of ROWS, that is count on <env>
TDC235Over 1,000,000 membersSame cause, past the point where it is worth running. Reduce the pool, or move the number to <env count="…">
TDC236A pool reads a pool declared below it, or itselfPools are built in declaration order, so a pool can only read the pools above it. Move the one it reads up. That order is also why a cycle between pools cannot be written down
TDC241Two pools declared under one nameA pool is reached by name, so two cannot share one. The second used to replace the first in silence, and the only sign was a TDC193 in the block about a field that "does not exist"

Three numbers in this range were reserved while pools were being designed and will stay unused, so the gaps are declared rather than silent:

  • TDC227filter= naming a column that does not exist. A bare word in the expression language has always been a string literal, and that is what filter="clinic == North" uses to say "northern only". A typo and a literal are the same thing written down, so the check would put an error on working configs. Where the literal is a certain mistake — no member could ever hold that value — TDC225 says so instead, without guessing.
  • TDC228${{Pool.field}} addressing a pool without going through a reference. TDC193 already reports it as a name that resolves to nothing, and a second code for the same sentence is not worth the number.
  • TDC233 — no candidate passed filter= on row N, for expressions richer than a simple equality. That refusal happens and is worth having; it just is not a diagnostic code. It compares against a value that only exists once the row is being built, so it belongs to the run, and the run's message names the row and the value that matched nobody.

Running totals

See accumulate= and <gen type="running">.

CodeFires whenFix
TDC237accumulate= on a generator with no repeat=There is no list to accumulate. Add repeat="N", or drop accumulate=. (type="running" is exempt — it accumulates down a column)
TDC238accumulate= names an operation that does not existOne of sum, min, max
TDC239<gen type="running"> does not say what (of=) or how (accumulate=) to accumulateA running total reads another column and draws nothing of its own, so both are required
TDC240of= or reset= names a column not declared aboveThe total is built from a column that already exists — the same rule parent= follows

<compute>

CodeFires whenFix
TDC180A tag inside <compute> that the compute language does not have, or a predicate written outside <test>The message names the tag. Check it against the compute reference — a predicate such as <eq> is valid only inside <test>
TDC181<current>, <current_index>, or <acc> is used outside its iteration bodyThey exist only inside a <do> (or a <reduce>'s <do>)
TDC182<use name="X"> names no enclosing <let>Wrap it in <let name="X">…</let>, or fix the name
TDC183A compute op that takes exactly two operands got another numberOnly <divide> and <mod> are binary — a third operand has no meaning there. <add>, <subtract> and <multiply> are variadic: <add> over three operands sums all three, and over none it is 0 (<multiply> is 1)
TDC184<choose> has no <otherwise> branchAdd <otherwise> — every record needs an answer
TDC185A <let name="X"> shadows an outer binding of the same nameRename one — the inner binding would hide the outer one
TDC186<encode>: unknown encodingOne of: base36, ascii, unicode, hex, binary, octal
TDC187A predicate is missing its wrapper child<when> wants <test>, <choose> wants <then> — the message names the pair
TDC188<int v="…"> isn't a whole numberWrite a whole number; for text, use <str v="…"/>
TDC189<compute> has more than one <result>Keep a single <result> — the earlier ones would be dropped

<mix>, <switch>, fixtures

CodeFires whenFix
TDC120<mix> has no <case>A mix needs branches to pick between
TDC121A percent on a <mix>/<switch> has more entries than there are casesOne percentage per case
TDC122A percent entry on a <mix>/<switch> isn't a non-negative numberEvery filled position has to be a number
TDC123The percent values on a <mix>/<switch> don't add up to 100Adjust them to total 100
TDC124<mix> has a child that isn't a <case>Only <case> belongs there
TDC125<case> has an unknown childAllowed: <data>, <gen>, <mix>, <switch> — a nested <switch> inside a branch is a first-class construct (see TDC245)
TDC131A fixture holds a tag it does not accept, or a <data> with no <line> around itA fixture body is made of <line>s. A bare <data> used to validate and render nothing at all
TDC132A tag that doesn't belong there sits inside <line>The output block is for layout — generators live in <env>
TDC133<switch> has no onName the sequence being switched on
TDC134on names a sequence, or a field of one, that doesn't existCheck the name — the message says which half is wrong
TDC135<switch> has no entriesAdd a <map>, <case>, or <default>
TDC136(warning) A <map> row isn't KEY:VALUE — the bad row is skipped and the rest of the map still appliesOne pair per entry, separated by a colon
TDC137A <case> inside <switch> has no isis is the branch key
TDC245name on a <switch> written inside a <case>The nested form contributes a value to that branch; only an env-level <switch> becomes a column

Dates

CodeFires whenFix
TDC150Only one of from / to is givenGive both endpoints or neither
TDC151The date value doesn't parsevalue="2020-01-01..2025-12-31", "birth", "today", "now"
TDC152A format token is unknownSee the token table
TDC153local names a locale with no date dataBuilt in, twenty-four of them: ar, cs, de, el, en, es, fi, fr, hi, hu, id, it, ja, ko, nl, pl, pt, ru, sv, th, tr, uk, vi, zh-cn. Nineteen also answer to a three-letter alias (ara, ces, deu, ell, eng, spa, fin, fra, hun, ind, ita, jpn, kor, nld, pol, por, tur, ukr, vie); hi, ru, sv, th, zh-cn have none
TDC154precision isn't a supported stepSee precision

While rendering

These are raised during generation rather than validation — the config is well-formed, but the combination it asks for can't be carried out.

CodeFires whenFix
TDC160row="…" is used on an inline <gen>Row linking needs a <sequence>
TDC161Weighted advanced_regex choices are used inlineExact percentages need the whole column — move it into a <sequence>
TDC162An inline counter's value or step isn't numericvalue="1" step="2"
TDC170A data-pack file can't be loadedThe message names the file — see Writing your own
TDC171(warning) A data-pack file lands at no address, so it is skippedAdd address: or locale: to its header, or move it under a locale folder
TDC200(warning) The estimated memory use is a large share of this machine's RAM — the run continuesFor very large sets, use mode="disk", which keeps memory flat
TDC201The estimated memory use is more than this machine's RAMLower count, batch the run, or use mode="disk"
Three of these cannot be reached from a config

TDC160, TDC161 and TDC162 describe an inline <gen> — one written directly inside <line> rather than in a <sequence>. Validation refuses that shape first, with TDC131 (a <gen> is not allowed inside <line>) or TDC013, so a real config never gets far enough to raise them. They are reachable only through the low-level render(parse(src).tree) export, which walks an unvalidated tree on purpose. That is also why the four ports do not have them: they compile a config into a model that has no place to put such a <gen>.

Formatting and modifiers

CodeFires whenFix
TDC190case isn't a known transformupper, lower, capitalize, title
TDC191order is neither random nor sequentialThose are the only two values
TDC192An interpolation filter is unknownSee Masks & case
TDC193${{Name}} or ${{Name.field}} names nothing that was declaredIt would print literally — the whole reference is checked, field and all
TDC193(second meaning) anomaly_flag= on a <gen> with no anomaly=The flag column marks which rows were made outliers, and nothing made any. Add anomaly="p", or drop the flag
TDC194A typed <data> has no nameOnly a named <data> becomes a column
TDC195repeat isn't a count or a rangerepeat="3" or repeat="1..5" (0 to 64)
TDC196repeat is used on a <mix>A mix picks one branch; it doesn't produce a list
TDC198separator without repeatIt joins repeated values, so there have to be some
TDC199A mask index is malformedIndices are 0-based and ranges use ..x[0..3], w[-1]
TDC202flag is set but no <case> is marked anomaly="true"The column would be all-negative — mark the outlier branch
TDC203flag is used on a nested <mix>Only a named env-level mix carries the answer column
TDC204repeat is used on a generator that can't repeatThe message names the type
TDC206each="" names no sequenceName the list to walk
TDC207each names a single-value sequenceIt has to be a list — add repeat to the source
TDC209A named <data> sits inside an each= lineThat line produces several rows, so a column name is ambiguous
TDC211weight is used on a generator other than fileWeights come from a CSV column
TDC212weight without columnThe weights live in a second column, which has to be named
TDC213weight is combined with orderorder walks the rows by position; weighting picks them by frequency
TDC242anomaly or missing isn't a number in [0, 1]Both are a SHARE of the values: anomaly="0.05", missing="0.1"
TDC243anomaly on a value list with no number in itAn anomaly multiplies a number, so a list of words comes back unchanged
TDC246anomaly_flag on a <gen> inside a <case>A case body is several parts joined, so a flag on one part doesn't describe the row — put flag="NAME" on the <mix> instead
TDC247step on a <gen type="date"> is not a step it can walk, or mixes a calendar unit with a fixed oneWrite 15m, 1h30m, 2d, 3mo, 1y — units s, m, h, d, w, mo, y; a bare number means days
TDC248step without order="sequential" on the same <gen>Nothing walks the range — the dates are still drawn at random. Add order="sequential", or drop step
TDC249weekdays names a weekday that does not existsun, mon, tue, wed, thu, fri, sat — a span like mon..fri or a list like sun,wed
TDC250weekdays with a step of a whole number of weeks, or a calendar stepTwo reasons under one code. A whole number of weeks fixes the weekday, so the filter matches every row or none. A calendar step does the opposite — 1mo walks Thursday, Sunday, Sunday, Wednesday — so which rows survive would follow the calendar rather than the config
TDC252peak_at on a <gen type="timeseries"> is not a numberpeak_at is the row the seasonal wave peaks on, counted like periodpeak_at="182" over period="365" puts the peak at the first of July
TDC253peak_at with no period on the same <gen>A wave needs a length before it can have a highest point. Add period, or remove peak_at
TDC251(warning) A percent share asks for less than one whole rowpercent is an exact quota over the rows that reach it, so 10% of a five-row subset asks for half a record. Half a record cannot be emitted: the branch fires once or not at all, and the seed decides which. Raise the share, or raise count
TDC254A walk that has no stride: a RANGED repeat="2..5" beside order="sequential", or a walked date with any repeat=A fixed repeat="4" works — the row takes four values off the walk. A ranged one has no fixed number of values per row, so row 5 would start wherever rows 0 to 4 happened to leave off. A walked date carries an instant beside its text, and a row holding several dates has no single one to give of= and plus=
TDC255decimals= together with include= or exclude=Drop one. A set built by include/exclude holds whole numbers and the pick is uniform over them, so there is nothing fractional to round — the engine was quietly emitting integers
TDC256A mask with no pattern — <mask> without pattern=, or ${{X|mask}} with no argumentGive it a pattern. Without one the mask keeps nothing and returns the empty string, so the column comes out blank
TDC257An if= expression calls a function that is not thereEither a typo, answered with the near name, or one of sin, cos, exp, log and their kin, answered with the reason: every host language computes those slightly differently, and a comparison turns the last bit into a different row. Available today: abs, ceil, floor, max, min, round, trunc
TDC258A function in an if= expression is given the wrong number of argumentsabs, ceil, floor, round and trunc take exactly one; min and max take as many as you give them
TDC259A [list] sits somewhere other than the right of inA list is a set of values to test against, so it only means something as Country in [US, CA, MX]. On its own it has no value for the condition to be
TDC260at() is given something that is not a listA repeat list reaches an expression as its joined text, so at(Items, 1) asks for the second element of a one-element list and answers with nothing. Cut it first: at(split(Items, ","), 1)
TDC261at() is given an index that is not oneAn index is a whole number, zero or more. Past the end is empty text on purpose — rows made by repeat="1..4" have different lengths — but -1, 1.5 and "one" are mistakes, and each of them used to produce that same blank column
TDC262<gen type="stat"> does not say what (of=) or which statistic (op=), or names one that does not existA statistic reads another column and draws nothing of its own, so both are required. op= is one of sum, mean, median, min, max, count, stddev; decimals= is 0 to 10
TDC263${{Name}} in an attribute that does not expand itInterpolation reaches the text inside <data> and <gen type="template" value=>, and nowhere else — anywhere else the braces are literal characters. To make one column depend on another, read it in an if= condition, or build the value in a <compute> sequence
TDC264<gen type="date" of="…"> is written wrongAn offset needs plus= (7d, 3..10d, 1..3mo, -10..-3d), written smallest bound first, in a unit step= also uses. The attributes that bound the generator's OWN draw — value, from, to, range, oldest, youngest, order, step — say nothing once of= has placed the date relative to another column, so they are refused rather than ignored. The mirror is refused too: plus= on a date with no of= has nothing to be far from
TDC265<assert> has no conditionAn assertion is the one construct whose whole worth is that it fails, and without that= it never can. Write the property the run must have, in the if= language, over whole-run columns
TDC266<assert> has no messagesays= is what a reader is told when it fires, months later, in a CI log. An expression on its own leaves them to work out what it was defending
TDC267(second meaning) uniq="true" on a <sequence> wrapping a <distinct><distinct> repairs one record so its fields differ; uniq then rearranges the finished columns and knows nothing about which pairings the repair ruled out, so it undoes them. Keep one — or give each field its own <sequence>, wrap those in <uniq>, and put the <distinct> at env level
TDC267uniq="true" together with mask=, case=, missing=, repeat=, separator= or anomaly=A draw without replacement produces the column directly and never reaches the layer that rewrites values, so the attribute could only ever be dropped. Applying it would break the other promise: a mask maps two distinct draws onto the same characters
TDC268if= on a <gen type="pool">A reference publishes a whole MEMBER, and a <gen> carrying if= becomes a conditional branch the pool resolver does not recognise — so no Ref.field column was registered and ${{Ref.name}} reached the output as its own literal text. Use parent= to leave rows without a member
TDC269if= on a <gen> inside a <case>A case body is several parts joined into one value, so a condition on one part has no value to fall back to. It was accepted and ignored, and the part appeared on every row — including the ones the condition excluded. Put the condition on the branch: <case if="…">
TDC270<tdc> holds a second <env> or <block>Both are read by taking the FIRST of their kind, so a second one is discarded whole — every sequence it declares, every line it lays out — while the run finishes looking healthy. Reported on the second one
TDC271percent= beside order="sequential"Walking the list in order fixes which value each row gets, so there is no share left to apportion. The percentage was accepted and dropped: percent="98,1,1" over a hundred rows came out 34 / 33 / 33
TDC272(warning) <env local=…> names a locale with no date translationsThe locale is a fine source of NAMES and ships no month names, so the dates render in English. Refused outright on <gen type="date" local=…> (TDC153) and silent here until now. Fires only when the format reads the locale — format="YYYY-MM-DD" is the same in every language
TDC273a filter argument the filter cannot useslice:5,2 ends before it starts and empties the column; slice:abc, group:abc, group:0, compact:1 and compact:99 leave the value untouched. group and compact with NO argument keep their documented defaults (3, base 36)
TDC274an argument on a filter that reads nonetrim, sql, upper, lower, capitalize and title are whole transforms; ${{X|trim:junk}} silently ignored the junk. Chain instead: ${{X|trim|upper}}
TDC275replace with nothing to look for${{X|replace}} and ${{X|replace:,to}} change nothing at all. Write both parts: ${{X|replace:from,to}}
TDC276a pinned pack parameter of the wrong widthAn identifier with a check digit has a fixed layout, so a wider or narrower part breaks it rather than shifting it. usa.finance.aba_routing prefix="12345" aborted the run; tail="678" wrote a six-digit non-number. Only reported where the width can be PROVEN from the pack's own body
TDC277decimals= with no range to roundWithout value= the generator produces a digit STRING — an identifier — so there is nothing to round. <gen type="number" length="4" decimals="2"/> emitted 4566, 5773, 5192
TDC278decimals= beside length=A fractional value has no integer width to pad to, so length= was the one discarded: value="1..9" length="3" decimals="2" emitted 3.78, 2.89
TDC279first_zero="false" the range can never satisfyEvery draw from 0..5 is one digit, so a three-wide rendering always pads. The generator redrew a hundred times per row and emitted the forbidden shape anyway: 005, 002, 003. Only reported where the range PROVES it
TDC280two spellings of the same date rangevalue=, the from/to pair and range= say one thing, and the generator reads them in that order and stops. value="2020-05-05" from="1990-01-01" to="1990-12-31" produced 1990-05-11 and discarded the rest without a word. value="today", "now" and "birth" are spellings too
TDC281a date range that ends before it startsThe draw took the min and max of the two ends, so from="2020-01-01" to="2010-01-01" produced perfectly plausible dates from a range nobody wrote. plus="10..3d" has been refused as a typo rather than swapped since it was written; this is the same typo
TDC282order="sequential" on only some members of a row= linkEither give every member of the link order="sequential", or drop it — a mixed link stops reading one line per record
TDC283anomaly_flag on a <gen> that is only one part of its <sequence>The flag records which ROWS were made outliers, and a sequence built from several parts — a second <gen>, a <data> literal, or a name= that makes this gen a field — has no row-level column to put it in. Move the <gen> into a <sequence> of its own; that also gives you the value as its own column. The same reasoning as TDC246, one level out
TDC284(warning) secret= written into the config, or an empty oneA key in a config travels wherever the config does — into version control with it. secret="env:TDC_HTTP_SECRET" reads it from the environment, secret="file:~/.tdc/service.key" from a file the repository does not hold. A literal is a WARNING, because a service on 127.0.0.1 for an afternoon is a real use; secret="" is an error, because signing with nothing produces a signature anyone could forge
TDC285A drawing attribute whose value is not one of its words, or not a numbermode=, interp=, spread= and decimals= were read only at render time, so check called mode="banana" valid and the run then refused it — the one place check did not answer "would this run?". Allowed: `mode="signal
TDC286<is_digit> or <encode> was handed <field name="_count"> or <field name="_total">Those two fields arrive as NUMBERS; both tags want one character of text. <is_digit> answered "no" on every row — including the rows where the count is a single digit — and check said nothing; <encode> stopped the run with "expected a single-character string", naming no file and no line, on a config check had also called valid. Compare the number with <equals> or <less_than>, wrap it in <concat> for <encode>, or put the character you mean into a <str>
TDC287<equals>, <greater_than> or <less_than> was given a <str> literal that is not a numberThe three comparisons work on numbers. A <str> holding digits is read as the number it spells — <equals><str v="7"/><int v="7"/></equals> is true — so only a literal that is not a number is refused. That one used to stop the run with "expected an integer in <equals>, got the string …", naming no file and no line, on a config check had called valid. Only literals are checked: what a <field> will hold is not known before the run
TDC288<var> — the tag was renamed to <use>It never declared anything: <let> binds a name and this reads it back, which is what the new name says. Without a refusal of its own the old spelling fell through to "unknown compute tag", which says the spelling is wrong and not what the right one is. The name= attribute is unchanged
TDC289distinct= was given something other than true or falseThe attribute has two spellings and no third meaning. Treating an unrecognised word as false would leave a config that asks for distinct values and quietly gets repeats
TDC290distinct= with no repeat=One value cannot repeat itself, so the attribute would be read and then do nothing. Add repeat="N" or repeat="A..B", or drop distinct=
TDC291percent= and distinct= on the same <gen>percent= promises exact proportions across the whole run; distinct= trades that promise away for a guarantee inside each row. Both cannot hold, so neither is silently dropped. For proportions over list LENGTHS, put them on a <mix> or <switch> outside, with repeat= on the <gen> inside
TDC292repeat= under distinct= asks for more values than the list can offerFive values cannot yield six different ones. Reported before the run where the pool is in the config (type="text", a whole-number range, a one-character symbol set); at run time where it is not (a pack file, a CSV column, a regex), since those are only read while generating
TDC293<gen type="pattern"> without y_range=A drawing has no scale of its own — the same curve leaves one tool running 0..100 and another 0..10002345345. y_range="min..max" is what those coordinates mean: it becomes the floor and ceiling of the drawing's canvas. Without it every answer would be a guess about somebody's export settings, so the attribute is required rather than assumed
TDC294<gen type="formula"> without expr=, or with an expr= that does not parse, or a decimals= outside 0..10A formula IS its expression, so there is nothing to compute without one. The expression is the same little language as if= — see Expressions. A name inside it that is not a column declared above raises TDC240 instead, the same code running and stat use for the same rule
TDC295if= on a running, stat, formula or date-offset columnThese are built once, for the whole run, in declaration order — an if= asks for a value chosen row by row, and the two cannot both be true. Put the condition where the value is USED (<data if="…">), or compute the column unconditionally and branch on it afterwards
TDC296A running, stat, formula or date-offset column, or a <compute>, inside <uniq> or <distinct>A group REARRANGES finished columns until each record is unique. A drawn value means the same wherever it lands; a computed one describes the row it was computed for, so moving it makes the arithmetic wrong. Put the group around the columns this one READS and leave the computed column outside it — it follows whatever the group arranges
TDC297Two readings of one file at once — read="quantile" beside weight=, row= or order="sequential"; a misspelled read=; sample= without itweight= puts the shares in a second column, row= links several columns to one LINE, order="sequential" walks the list in order, and read="quantile" says the values ARE the distribution and a row lands anywhere on the sorted sample. Keep one reading: a countable value wants weight= and its exact quota, a measured one wants the quantile read
TDC298One row= key over two different filesA link is one LINE of one file, so there is no line that belongs to both. Point every member of the link at the same src=, or give this one its own row= key
TDC299(warning) uniq="true" over 100,000 rowsKeeping a promise about the finished column costs memory that follows count, on every engine — the cost belongs to the promise, not to one of them. About 250 bytes a value, measured: 2,000,000 rows cost about 477 MB, and a compound uniq measures higher still. A single drawn column pays twice, because drawing without replacement cannot be done a row at a time, so that shape also runs in memory whatever mode= asks for. It works; it is worth being deliberate about
TDC300fit= that is not a band, counts down, or sits beside points=/upper=/lower=fit="low..high" says what the drawing's own lowest and highest point become on the value axis — it is how a curve read from src= gets placed, since a file carries a shape and no units. Two numbers, smaller first; turning the drawing upside down is a different request. Beside typed points it is refused: 80 there already means 80% of y_range, so there is nothing left to place. Omit it and the drawing fills y_range
TDC301(warning) A share list that leaves a declared value at 0%A percent shorter than value is fine — what is left over goes to the positions you did not write, so value="a,b,c" percent="30,40" gives c the remaining 30. When the written shares already total 100 there is nothing left, and that value is declared and can never be drawn: percent="50,50" over 300 rows came out 150 a, 150 b, no c. A zero you write yourself — percent="50,0,50" — is taken at its word and says nothing
TDC302A <distinct> or <uniq> over <gen type="pool"> references that cannot mean anything: one beside an ordinary sequence, references to two different pools, or more references than the pool has membersA group over references compares WHICH MEMBER each row took, so the members must be comparable and there must be enough of them. Each of these three used to be accepted and then do nothing at all
TDC303A missing_when= that decides nothing: no condition at all, no missing= rate beside it, or a repeat= cell under itThe condition names the mechanism — missing_when="Age < 30" is MAR, missing_when="_value > 150000" is MNAR — so a written-and-blank one is a question nobody finished asking, and one with no rate has no draw to gate. A repeated cell holds several values on one row while the condition asks about one, and rather than guess which reading you meant it is refused. All three used to be accepted and quietly ignored
TDC304Seasonal lists that do not line up: amplitude= or peak_at= with a different number of entries from period=, or a 0 among several periodsperiod="7,365" amplitude="120,400" peak_at="5,182" describes the same two waves three times over, position by position, so a length that disagrees describes no wave anybody can draw — the extra entry used to be dropped and nothing said so. A single amplitude for waves of equal height is the one shorthand. period="0" alone means "no seasonal wave"; among several it is a wave with no length beside waves that have one
TDC305A noise_correlation= that cannot be honoured: outside −1..1, or with no noise= beside itIt is how much of one row's jitter carries into the next. At 1 the series would wander off and never come back — a random walk, not noise — and above 1 it grows without bound; both are refused rather than clamped. Without noise= there is nothing to correlate, so the attribute decides nothing
TDC306An <assert> carrying both that= and each=They answer different questions and are checked a different number of times: that= once, over whole-run values, and each= on every row. One tag with both leaves a reader unable to tell which of the two the sentence in says= describes. Write two assertions, each with its own says=, so a failure says which one broke
TDC307distinct="true" beside order="sequential"distinct= draws the row's values without replacement, and a walked row draws nothing — its values are decided by its position. Honouring both is impossible, and quietly ignoring one is how a config comes to claim something it never had
TDC308A condition on a <gen>if= or missing_when= — naming a column declared below itThe condition is answered while this column is being built, so a column further down does not exist yet. The two engines disagreed about what to do with that, and both answers were defensible: the in-memory engine read it as empty and the condition never held, while the streaming engine built the column on demand and the condition resolved for real. Move the <sequence> it names above this one. A condition read after the row is finished — <data if=>, <line if=>, <assert that=> — may name any column

See also