Skip to content

Unsupported constructs

The complete catalogue of what Parse reports through File.Unsupported, what triggers each one, and what is deliberately not flagged.

A report is not a judgement. Parse still succeeds and the document is still readable; only File.Bytes refuses, so you decide whether to warn, refuse or read-only. The how-to is Refuse unsafe documents.

The report

type Unsupported struct {
    Reason Reason
    Line   int    // 1-based line where the construct starts
    Detail string
}

String() renders as line 12: <reason> (<detail>), or line 12: <reason> when Detail is empty.

Order is not source order. ReasonFlowComment reports come first, in the order they appear in the file; a ReasonUndecodable report is appended after them, whatever line it names. Do not use [0] to mean "the first problem in the file" — it means "the first problem found".

Reason values

There are two, and their constant values are the sentences themselves — printing a Reason gives you readable text, not an identifier.

Constant Value
ReasonFlowComment multi-line flow collection with interior comments
ReasonUndecodable document parses but does not decode

Branch on the constant, not on the text.

for _, u := range f.Unsupported() {
    switch u.Reason {
    case yamldoc.ReasonFlowComment:
        // fixable by rewriting the collection in block style
    case yamldoc.ReasonUndecodable:
        // the document is broken; a rewrite will not help
    }
}

ReasonFlowComment — a multi-line flow collection with comments inside it

bounds: {
  min: 1,   # lower bound
  max: 10   # upper bound
}
line 1: multi-line flow collection with interior comments (collection spans lines 1-4)

Line is where the collection opened; Detail names the span. Re-emitting one of these swallows the closing delimiter into the comment and produces YAML that does not parse, so it is refused instead.

Rewrite the collection in block style, which has no such problem:

bounds:
  min: 1    # lower bound
  max: 10   # upper bound

Detection is a scan of the source text, not the parse tree — by the time the document is a tree, the layout that makes this case dangerous has already been lost. The scanner tracks quoting, so a # or a brace inside a quoted scalar is not mistaken for structure, and it skips the body of a | or > block scalar entirely.

Not flagged

Flow style on its own is fine. All of these round-trip:

Construct Example
A single-line flow mapping or sequence voice: &v {id: abc, stability: 0.6}
A comment beside a flow node tiers: [core, ingress] # fine
A comment above a flow node # describes the bounds
bounds: {min: 1, max: 10}
A multi-line flow collection with no interior comments bounds: {
min: 1,
max: 10
}
Braces or # inside a block scalar a JSON or template body under \|
--- inside a block scalar it is content, not a document separator

The multi-line collection without comments is accepted but reflowed onto one line on emit; see What is preserved.

ReasonUndecodable — the document parses but means nothing

The shape is legal and the meaning is not. Parse decodes every document after parsing it, and a failure there becomes a report:

a: *nope
line 1: document parses but does not decode (could not find alias "nope")

Detail is the decoder's own message and Line comes from the token it names, when it names one. An alias with no anchor is the case you will meet: it is invisible to the parser, because resolving aliases is a decode-time job.

There is no rewrite that makes this document safe — it is broken, and the right response is usually to tell whoever wrote it.

What this reason does not cover

The ReasonUndecodable doc comment in the source lists a duplicate mapping key alongside the dangling alias. With goccy/go-yaml v1.19.2 that is not what happens: the parser rejects duplicate keys outright, so

a: 1
a: 2

fails at Parse with mapping key "a" already defined at [1:1] and never reaches an Unsupported report. Handle it as a parse error.

What is not detected, because it is not detectable here

Unsupported covers constructs whose round-trip is unsafe. It says nothing about whether an edit you are about to make is safe. In particular it does not warn that a string you pass to Set will need quoting the emitter will not add — that is a separate hazard, described in Limitations.