[go-fan] Go Module Review: goccy/go-yaml #23213
Closed
Replies: 1 comment
-
|
This discussion was automatically closed because it expired on 2026-03-28T07:30:13.417Z.
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
🐹 This module is the backbone of gh-aw's YAML pipeline — 57 Go files import it, making it the single most widely-used third-party library in the codebase. Today's review surfaces one safety gap, a pending upstream upgrade, and several under-utilized features.
Module Overview
github.com/goccy/go-yamlis a pure-Go YAML library written from scratch as a superior alternative togopkg.in/yaml.v3. Key strengths over the standard library:gopkg.in/yaml.v3MapSlicefor deterministic field ordering (critical for workflow diffing)yaml.FormatError— pretty-printed errors with source line contextPathStringqueries on YAML documentsIndent,UseLiteralStyleIfMultiline,OmitEmpty, etc.Version in use:
v1.19.2(latest release, 2026-01-08)Current Usage in gh-aw
Usage Details (57 files)
Packages:
pkg/workflow/,pkg/parser/,pkg/cli/yaml.Marshal/yaml.Unmarshalyaml.MarshalWithOptions(data, Indent(2), UseLiteralStyleIfMultiline(true))yaml_options.goDefaultMarshalOptions, used inMarshalWithFieldOrderyaml.MapSlice/yaml.MapItemyaml.go—OrderMapFields,MarshalWithFieldOrderfor deterministic field orderyaml.FormatError(err, false, true)parser/yaml_error.go— pretty error messages with source contextyaml.EncodeOptionyaml_options.go—DefaultMarshalOptionsconstantThe project makes excellent use of
MapSlicefor deterministic GitHub Actions YAML output andyaml.FormatErrorfor user-friendly error messages.Research Findings
Recent Updates (since v1.19.2 — unreleased on master)
The repository has 4 commits on master since the v1.19.2 release (as of 2026-03-10). A v1.19.3 release is likely forthcoming:
fix(token): Quote strings starting with:for Ruby/Psych YAML compatibility:fix(encoder): Anonymous unexported struct crashThe colon-quoting fix is notable: before this fix, a string value like
:8080would not be quoted by the encoder, causing Ruby's YAML parser (Psych) to treat it as a Symbol. This affects GitLab CI, GitHub Actions tooling, and other Ruby-based DevOps integrations.Best Practices from Maintainers
InterfaceMarshaleroverBytesMarshalerfor repeated marshaling of complex objects (avoids extra decode round-trip)yaml.NewDecoderwithyaml.DisallowUnknownField()for strict user input validationyaml.OmitEmpty()encode option as alternative to manual nil/empty filteringImprovement Opportunities
🏃 Quick Wins
1. Migrate
renderStepFromMapto useyaml.MarshalWithOptionscompiler_yaml_helpers.go:337contains a manual YAML serializer usingstrings.Builder. It does NOT go through goccy/go-yaml and therefore misses safe quoting for values containing:,#, or other special characters. Every other marshal path in the codebase usesConvertStepToYAMLorMarshalWithFieldOrder. TherenderStepFromMapfunction is an inconsistency that could produce invalid YAML for edge-case step values.2. Upgrade to v1.19.3 when released
Watch for the next release that includes the colon-quoting fix. The project is currently on the latest release but master has correctness improvements. Consider pinning to master if the colon-prefix issue is observed in practice.
✨ Feature Opportunities
yaml.DisallowUnknownField()on user-facing Unmarshal callsCalls that parse user-provided frontmatter or workflow YAML (e.g., in
pkg/parser/frontmatter_content.go:63) use bareyaml.Unmarshal. Switching toyaml.NewDecoderwithDisallowUnknownField()would catch typos in frontmatter keys and produce goccy's beautifully-formatted errors immediately.yaml.RawMessagefor deferred schema validationAdded in v1.19.0,
yaml.RawMessageenables partial decoding (decode top-level structure, defer nested values). Useful in schema validation paths where only specific top-level keys need to be inspected before expensive full-document processing.📐 Best Practice Alignment
CleanYAMLNullValuesregex workaroundyaml.go:300post-processes marshaled YAML strings with regex to strip: null. The idiomatic goccy approach for struct-based types is theomitemptystruct tag or theyaml.OmitEmpty()global encode option (added v1.18.0). For themap[string]anyuse case the null values come from explicitnilentries — filtering them before building theMapSlicewould be cleaner:Consistent import alias
pkg/cli/compile_permissions_integration_test.gousesgoyamlas the import alias while all 56 other files use the defaultyamlpackage name. Minor but worth aligning.🔧 General Improvements
formatYAMLValueover-quotesyaml.go:314wraps every string value in single quotes regardless of whether quoting is needed. This is used in contexts where goccy/go-yaml isn't called for the formatting. While safe, it produces slightly noisy YAML ('true'instead oftrue-as-string). Consider whether these call sites could route through goccy/go-yaml's marshaling instead.Recommendations (Prioritized)
renderStepFromMap— migrate it to useConvertStepToYAML/yaml.MarshalWithOptionsto close the unsafe-quoting gap. Low risk refactor since the test suite should catch regressions.yaml.DisallowUnknownField()for better user error messages on invalid keys.CleanYAMLNullValueswith pre-marshal nil filtering as a cleanup item.Next Steps
:to assess urgency of colon-quoting fixrenderStepFromMapcan be replaced withConvertStepToYAMLyaml.DisallowUnknownField()to frontmatter parsingReferences: §23635760496
Module summary saved to:
scratchpad/mods/go-yaml.mdBeta Was this translation helpful? Give feedback.
All reactions