Build1 distinct publisher3 min readPublished
A dev.to post swept 146 uses of IFS=$'\t' read in one codebase and found 14 live defects. The corrupt parse and a legitimate one have identical shape.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Fourteen live defects across 146 call sites is a 9.6 percent hit rate [1], and the interesting number is the other 132 [2]. The sweep called them not-live [7]; it did not call them correct. A site of this shape is only fine while the thing feeding it never emits an empty field, and that is a property of the data, not of the script. The pattern matched the whole population, not a sample [7], so the denominator is honest, but the numerator is a snapshot of which inputs happened to contain a blank cell during one audit.
The most instructive of the fourteen is the notifier. It read `jq -r @tsv` output where a null author renders as an empty middle field, and the alert went out reading "by <timestamp>" with an empty body [8]. The same file already defended against that exact null on a different code path [8]. Whoever wrote it knew the field could be empty. They did not know that `read` would spend the emptiness on the following column.
Empty fields are also not a synthetic edge case you can wave off. `prctl(PR_SET_NAME, "")` makes `/proc/PID/stat` read `1489683 () R`, so the comm field of a process table can genuinely be blank, and in that codebase a real runaway process read back as an undecided candidate and was never reported [9]. Two of the listed defects wrote their wrong values into durable files: a fabricated `"ip":"1"` into a peer status file, where the `1` was the next column [10], and an author name appended to a dedupe file as if it were a comment id [11].
The mechanism is one sentence of POSIX. When IFS contains whitespace characters, runs of them collapse to a single delimiter and leading and trailing ones are stripped, and tab is whitespace [3], so `IFS=$'\t'` asks for splitting on runs of tabs at exactly the moment a TSV file is using two adjacent tabs to say "nothing here" [3]. Swap in a delimiter the shell does not classify as whitespace and the same `read` preserves the empty field [4]. That is available where you own the emitter. Where you do not, the post's answer is to stop asking `read` to split at all: walk the line yourself with `${line%%$'\t'*}`, assign each name in turn, and let the last name take the remainder [12].
Cost of the fix, honestly stated: every read site becomes a call into a helper that has to exist in scope, and the helper has to be exercised at each position an empty column can occupy, because the failure is positional. Cost of not fixing it: nothing visible, which is the problem. This is one author, one codebase, self-reported, and the defect list is descriptions rather than diffs. The two `printf` lines are a different matter. `printf 'alpha\t\tgamma\n'` piped into that idiom returns `gamma` in `b` [2], and it reproduces in any bash in about four seconds, which is cheaper than believing me.
Ranked by verification strength, evidence, and original report placement.
The proposed fix is a split_tabs helper that splits on the delimiter itself instead of asking read to do it, taking the line and a list of variable names, assigning ${line%%$'\t'*} to each in turn and giving the last name the remainder.
The canonical shell idiom for reading tab-separated columns is IFS=$'\t' read -r a b c, used with output from jq -r @tsv, git for-each-ref --format, ps --format and anything piped into awk -F'\t'.
printf 'alpha\t\tgamma\n' piped into { IFS=$'\t' read -r a b c; } yields a=[alpha] b=[gamma] c=[]; three columns went in with the middle one empty, and gamma came out in b.
Per the POSIX shell spec, when IFS contains whitespace characters, runs of them are treated as a single delimiter and leading and trailing ones are stripped; tab is whitespace, so IFS=$'\t' means split on runs of tabs, while a TSV file's convention for an empty cell is exactly one tab followed by another.
printf 'alpha||gamma\n' piped into { IFS='|' read -r a b c; } yields a=[alpha] b=[] c=[gamma]; the empty field survives because | is not whitespace.
An empty trailing column, printf 'alpha\tbeta\t\n', also yields two populated variables and one empty one (a=[alpha] b=[beta] c=[]), so the corrupt parse and the legitimate one have identical shape.
Follow any of these and your For You feed starts watching them — no settings page required.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Mechanism proven, impact untriangulated
The core technical claims are as well-evidenced as a blog post can make them: re-run transcripts for empty-middle, empty-trailing, empty-leading and full rows, a non-whitespace-delimiter control case, an explicit POSIX rule that explains the behaviour, and a published helper with its output. Any reader can reproduce them. The impact half — 146 sites, 61 files, 14 live defects, five narrated incidents — comes from one unnamed codebase with no repository, sweep script, logs or defect identifiers, and there is no second publisher in the cluster to corroborate anything.
Problem pattern widespread in one codebase; fix barely deployed
The only measurable adoption is internal to the author's environment: 146 existing call sites of the flawed idiom in one codebase, and an attempted rollout of the fix as a sourced library that initially silenced the test gates of three rewired tools. Nothing in the cluster documents use of split_tabs outside that codebase, no downstream users, forks, package, or third-party confirmation. The claim that the idiom is 'one line everybody has written' is plausible but unquantified here.
Slightly understated relative to what is shown
Presentation is restrained: no product, no vendor, no benchmark inflation, an explicit statement that listings were re-run, and an admission that the author's own first fix was wrong. The demonstrated mechanism fully supports the central argument, so the substance is if anything undersold relative to how quietly it is packaged. The small positive pull is the generalizing title and the 'your TSV parser' framing, plus a defect rate implicitly extrapolated from one unnamed codebase that no reader can check.
Low: independent author, no product to sell
The cluster's single source is an individual developer post on dev.to. There is no vendor, sponsor, commercial product, pricing, hiring pitch or funding event anywhere in the material; the recommended fix is a ten-line inline shell function rather than something the author monetizes. The residual incentive is ordinary authorial credit for a dramatic finding, which is consistent with the unverifiable defect counts being stated more confidently than they can be checked.
High on mechanism, low on scale
One publisher, one article, no corroboration — but the part that matters most is checkable at a terminal and anchored to the POSIX shell specification, so confidence in the technical core is high. Confidence in the story's quantitative frame (how common the defect is, what fraction of real call sites are affected, whether the five incidents happened as described) is low, and adoption of the remedy is essentially undocumented outside the author's machine.
build
Bedrock's evaluation modes grade what they can see, and the dataset outlives both1 distinct publisher
build
A cost monitor overcounted 4.9x, then went dark for a week when set -e did its job1 distinct publisher
build
Parallel coding agents on Windows break at the home directory, not the launcher1 distinct publisher
build
Your reviewing model is reading the diff when it should be reading the session1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 25, 2026