Skip to content

encoding/json/v2: remove recursive nature of string tag option #79065

Closed

Description

@dsnet

Proposal Details

The current prototype of json/v2 allows the string tag option to be recursive. For example:

json.Marshal(struct{
    Foo []int `json:",string"`
}{Foo: []int{1, 2, 3}})

would result in:

{"Foo": ["1", "2", "3"]}

This is in contrast to v1 behavior, which silently ignore the string tag option on composite Go types.

In the working group, we decided to remove the recursive nature of string since none of the other tag options are recursive in nature. With typed struct tags coming in the horizon, it increasingly looks like most tag options would be non-recursive in nature (i.e., they only affect the immediate field value). Of course, there exist reasonable use-cases where you want an option to be recursive, but we would probably design a typed-struct tag API to express that intent. Thus, the general precedence is that tags are non-recursive by default.

We will remove support for string tag option on composite types and (if running under v2-semantics, to instead report a runtime error).

Activity

  1. moved this from Needs triage to Implementing in json/v2 working groupon Apr 30, 2026
  2. added
    LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a tool
    on May 1, 2026
  3. aclements commented on May 7, 2026

    @aclements
    Member

    @dsnet , FYI, I'd prefer this to be fixed before we flip the GOEXPERIMENT flag.

  4. self-assigned this
    on May 15, 2026
  5. added this to the Go1.27 milestone on May 15, 2026
  6. prattmic commented on May 15, 2026

    @prattmic
    Member

    We will remove support for string tag option on composite types and (if running under v2-semantics, to instead report a runtime error).

    I agree that v2 should report a runtime error if the string tag appears on an unsupported type, but it is unclear to me which option this behavior should be associated with.

    The primary option regarding the string tag is encoding/json.StringifyWithLegacySemantics, which will have the following baseline behavior:

    encoding/json.StringifyWithLegacySemantics(true) (v1): The string tag takes effect on fields where the top-level type is a bool, string, numeric kind, or a pointer to such a kind.

    encoding/json.StringifyWithLegacySemantics(false) (v2): The string tag takes effect on fields where the top-level type is a numeric kind, or a pointer to such a kind.

    (i.e., v2 drops bool and string)

    One option is to tie the errors to this option. So true/v1 ignores the tag on invalid fields and false/v2 reports an error if the tag appears on an invalid field.

    Alternatively, we could tie the errors to encoding/json.ReportErrorsWithLegacySemantics. So true/v1 ignores invalid fields, and false/v2 reports errors.

    I lean slightly towards this as the better choice, since ReportErrorsWithLegacySemantics says "if a Go struct contains type errors(e.g., conflicting names or malformed field tags), then such errors are ignored and the Go struct uses a best-effort representation. In contrast, the v2 semantic is to report a runtime error."

    I suppose that placing the string tag on the wrong type of field qualifies as a "malformed field tag"?

    What gives me pause is that the implementation of StringifyWithLegacySemantics(true) does not currently report errors if ReportErrorsWithLegacySemantics(false) (there should be an else if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { return err... } case). It's unclear to me if this is an oversight, or I have misunderstood the intention.

    cc @dsnet @aclements @neild @ChrisHines let me know if you have an opinion.

  7. ChrisHines commented on May 15, 2026

    @ChrisHines
    Contributor

    I think tying the error to either of those settings can be justified. Based on the current documentation for the two options, though, I think it is a slightly better fit to tie the errors to encoding/json.ReportErrorsWithLegacySemantics.

  8. gopherbot commented on May 18, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/779300 mentions this issue: encoding/json/v2: remove recursion and error on string on unsupported type

  9. added a commit that references this issue on May 19, 2026
    e9edbce
  10. gopherbot commented on May 19, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/779940 mentions this issue: encoding/json/v2: add string option hint optimization

  11. gopherbot commented on May 28, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/784040 mentions this issue: encoding/json/v2: use option flags to signal presence of tags

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

Metadata

Metadata

Assignees

Labels

LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolProposalrelease-blocker

Type

No type

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions