Build1 distinct publisher3 min readUpdated
YAML 1.2 killed the Norway problem in 2009. A dev.to post makes the operator's point: if half your parsers never moved, the file is read two correct and incompatible ways, silently.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
YAML 1.2 removed the implicit booleans that turn `country: NO` into `false`, and it did that in 2009 [1]. A post on dev.to argues the part that actually costs an afternoon is downstream of that fix: a large share of parsers in a working pipeline never moved to 1.2, so the failure is not one parser being wrong, it is two parsers in the same pipeline being right in different ways on the same file [1][2]. The count is the useful bit. According to the post, a fairly ordinary Python-and-Kubernetes shop runs at least four YAML parsers [3]. You do not need four repos to get the split, either: js-yaml v3 is 1.1 and v4 is 1.2, so a repo old enough to still carry v3 alongside a newer package on v4 has both specs inside a single `node_modules` [4]. Six lines cover most of it in practice: `country: NO` (1.1 `false`, 1.2 `"NO"`), `enabled: off` (`false` / `"off"`), `mode: 0644` (`420` as octal / `644` as decimal), `timeout: 12:30` (`750` base 60 / `"12:30"`), `scale: 1e5` (string / `100000`), and `version: 1.10`, which is the float `1.1` under both [5]. Five of the six diverge on spec version [1]. Three of them are silent data corruption with no error anywhere [6]. `mode: 0644` is the one that looks safe. A 1.1 parser reads octal and hands you `420`, which is the mode you meant; a 1.2 parser reads decimal `644`, which is `1204` in octal, which is nothing you wanted [5][7]. `12:30` becoming `750` is the sexagesimal type, a 1.1 feature that existed so you could write `1:30:00`, removed in 1.2; any port pair or `HH:MM` in a config is exposed [8]. Two more are not version differences at all. `1.10` is a float everywhere and floats have no trailing zeros, so a version pin silently becomes `1.1`, with no spec version in which that behaves [9]. Duplicate keys are an error under 1.2 and silent last-one-wins under PyYAML, so the same key at line 40 and line 380 of a 400-line values file goes unreported [10]. The expensive shape is a chain, not a file. The post's example: `feature_legacy_import: no` in `group_vars/prod.yml`, PyYAML resolves `False`, Jinja renders `False` into a ConfigMap as the string `"False"`, and the Go service calls `strconv.ParseBool`, which succeeds. Someone later "fixes" the vars file by quoting it to `"no"`, `ParseBool("no")` returns an error, and the code treats the error as `false` with a logged warning nobody reads. The flag is off both times, for two different reasons, and only one of them is the one that was configured [11]. Do not expect the linter to hold this. `yamllint` has a `truthy` rule that flags bare `yes`/`no`/`on`/`off`, and it is free to turn on [12], but it does not check octal ambiguity, sexagesimals, exponent notation, version truncation, or what two specific parsers each make of the file, because it reads YAML as text rather than values [13]. There is also a layer below the spec: the 1.1 type repository lists bare `y` and `n` as booleans and PyYAML's resolver deliberately does not, so "it works in my parser" is a claim about one library's resolver, not about YAML 1.1 [14]. The post's remedies, in its order of value: single-quote the ambiguous strings only (anything matching `y|n|yes|no|on|off|true|false` in any casing, leading zeros, colons, number-shaped non-numbers), because single quotes pin a string under both specs [15]; schema-validate the parsed object rather than the text, since a JSON Schema catches `420` where you wanted `"0644"` and a text linter cannot [16]; `yaml.safe_load` plus explicit coercion at the boundary instead of trusting the resolver [17]; and pin the parser version in the lockfile knowing which spec it implements, since js-yaml v3 to v4 is a behaviour change [18].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
YAML 1.2 fixed the Norway problem (country: NO resolving to false) in 2009, but a large share of the parsers in a typical pipeline never moved to 1.2.
The interesting failure is not one parser being wrong but two parsers in the same pipeline being right in different ways on the same file.
js-yaml v3 implements YAML 1.1 and v4 implements 1.2, so a repo old enough to still be on v3 alongside a newer package on v4 has the spec split inside a single node_modules.
Practical divergences: country: NO -> 1.1 false, 1.2 "NO"; enabled: off -> 1.1 false, 1.2 "off"; mode: 0644 -> 1.1 420 (octal), 1.2 644 (decimal); timeout: 12:30 -> 1.1 750 (base 60), 1.2 "12:30"; scale: 1e5 -> 1.1 "1e5" (string), 1.2 100000; version: 1.10 -> 1.1 (float) in both.
Three of the listed cases are silent data corruption with no error anywhere.
A 1.2 parser reads mode: 0644 as the decimal number 644, which is 1204 in octal, and which one is correct depends entirely on which binary opened the file.
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.
Specific and internally checkable, but single-source
The mechanism claims are unusually concrete for a single source: named scalars with both readings, the js-yaml v3/v4 spec boundary, the removed sexagesimal type, PyYAML duplicate-key behaviour, and the limits of yamllint's rule set. All of that is verifiable against specs and library behaviour, which lifts evidence above the midpoint. It is capped by there being exactly one publisher, no independent corroboration, and no data behind the prevalence and incident framing.
No adoption or deployment data supplied
Nothing in the supplied material measures adoption: no counts of YAML 1.1 versus 1.2 parsers in real dependency trees, no yamllint truthy-rule enablement rates, no users or downloads for the author's linter. The only adoption-adjacent item is the author's self-disclosed tool, which reports no usage at all, and the 'at least four parsers' figure is an assertion the author says most teams have never checked.
Mechanics land; prevalence framing runs ahead of the data
The technical core is close to aligned - the divergences, the sexagesimal removal, the duplicate-key asymmetry and the yamllint boundary are stated conservatively, and the post even credits the tool it is arguing past. The modest positive gap comes from the unquantified scale claims ('a large share', 'at least four', 'most teams have never counted') and from the closing pitch for the author's own linter, which is offered with no evaluation data.
Self-published author promoting their own linter
The piece is a self-published developer-platform post whose argument - that existing validators only tell you a file parses, never what it parses into - terminates in the author's own client-side linter and a companion background post. That is a clear promotional incentive to widen the perceived gap between yamllint and value-level checking. It is partly offset by transparent credit to yamllint's truthy rule and by claims stated precisely enough for readers to verify independently.
Moderate: mechanics reliable, scale and impact unverified
Confidence is moderate because the deterministic parts of the story are strong and independently checkable, while everything about magnitude - how many pipelines mix specs, how often this actually corrupts production config - rests on one self-interested source with no measurement and no corroborating publisher.
build
Your meter now runs on someone else's machine: signed receipts, fsync, and failing open1 distinct publisher
build
Count invalid JSON as a failed classification, and model choice becomes a reliability problem1 distinct publisher
build
Passing Schema Validation Says Nothing About Whether Your Agents Can Act Safely1 distinct publisher
build
Edge Kubernetes did not break on clusters. It broke on the assumptions under them.1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 20, 2026