Skip to content

Strings that YAML 1.1 reads as booleans or numbers are written unquoted ("NO" → NO, which Jekyll/PyYAML read as false; "12:30" → 750) #188

Description

@matt-edmondson

What's wrong

The serializer in Frontmatter/YamlSerializer.cs:36-40 is built with .WithQuotingNecessaryStrings() and no argument. That quotes only strings that are ambiguous under the YAML 1.2 core schema (true, null, 1.0, 007, and so on). It does not quote strings that are booleans or numbers under YAML 1.1:

  • yes, no, on, off, y, n, in any case
  • sexagesimal values such as 12:30
  • 1_000
  • 0b101

Every write path goes through this serializer: CombineFrontmatter (Frontmatter.cs:113), AddFrontmatter (:200), ReplaceFrontmatter (:222) and SerializeFrontmatter (:265). A string value with one of these spellings therefore comes out as a bare scalar.

#137 set out to keep strings from changing type for "Jekyll, Hugo, Astro, js-yaml, PyYAML". Jekyll (Ruby Psych) and PyYAML are YAML 1.1 parsers, so these values still change type for them.

Reproduction (at 23c87b1)

Caller-supplied values:

Frontmatter.AddFrontmatter("Body", new() { ["country"] = "NO", ["enabled"] = "yes", ["duration"] = "1:30" });
---
country: NO
enabled: yes
duration: 1:30
---
Body

Round trip of values that were quoted in the source:

Frontmatter.CombineFrontmatter(
    "---\nk0: \"yes\"\nk1: \"No\"\nk2: \"on\"\nk3: \"OFF\"\nk6: \"12:30\"\nk8: \"1_000\"\nk9: \"0b101\"\n---\nBody\n",
    FrontmatterNaming.AsIs, FrontmatterOrder.AsIs, FrontmatterMergeStrategy.None);

All seven values come back unquoted: k0: yes, k1: No, k2: on, k3: OFF, k6: 12:30, k8: 1_000, k9: 0b101. In the same run, strings that are ambiguous under YAML 1.2 ("01234", "1e3", "TRUE", "0x1F", ".inf", "~") do stay quoted.

How YAML 1.1 consumers read that output:

Value written PyYAML safe_load Ruby Psych / Jekyll YAML.load
yes True true
No False not checked
NO False false
on True not checked
OFF False not checked
12:30 750 45000
1_000 1000 1000
0b101 5 not checked

Why it matters

Static-site generators and scripts consume the frontmatter this library writes. A caller who writes the string "NO" (a country code), "yes" or "no" (an answer field), or "1:30" (a duration) gets a boolean or an integer downstream. This is the "Norway problem". A formatting pass also silently changes the type of values whose authors quoted them specifically to prevent this.

Suggested fix / acceptance criteria

Related: #137 (closed; covered the YAML 1.2 cases), #180 (open; preserving document scalar style).

Activity

  1. matt-edmondson commented on Oct 6, 2026

    @matt-edmondson
    ContributorAuthor

    Triage


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions