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¶
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:
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 boundsbounds: {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:
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
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.