Skip to content

encoding/json: potential compatibility issues with "inline" tag on existing types #79985

Description

@prattmic

Go 1.27 adds a new JSON "inline" struct tag as part of #71497. This tag specifies that the JSON object representation of this field is to be promoted as if it were specified in the parent struct. It is the JSON equivalent of Go struct embedding. A Go embedded field is implicitly inlined unless an explicit JSON name is specified.

In Go 1.27, this tag is supported by both the encoding/json and encoding/json/v2 APIs. Support in encoding/json is intentional to ensure that packages using new tags on their types don't implicitly require all of their dependents switch to the encoding/json/v2 API.

Even though this tag doesn't exist in 1.26, it turns out that it has widespread use throughout public Go code, particularly within the Kubernetes community. https://grep.app/search?q=%60json%3A%22%2Cinline%22%60 shows ~29k results for uses on the "inline" tag.

I do not know the original source of this tag in Kubernetes. It seems to have originated at some point and then got copied around. In fact, @liggitt has been removing uses of this tag since it didn't actually do anything (kubernetes/kubernetes#138260).

Regardless, Kubernetes uses encoding/json and many of these tags still exist, so there is a risk of behavior change when the 1.27 toolchain upgrade occurs and encoding/json gains support for this tag.

29k uses sounds dire, but the vast majority of uses apply the tag to an embedded field. Embedded fields are already inlined, so the "inline" tag has no impact to these fields.

I analyzed modules in the Go module proxy with at 3 transitive importers for uses of the "inline" tag on named fields. The full set of 2639 findings are here.

While I have not looked at every finding, some things I've found so far:

All told, I have not yet found any cases that are definitively broken by a 1.27 behavior change, but I do not have high confidence that there are none.

I'm creating this issue to discuss what we should do about this. Currently I see four options:

  1. Simply do nothing because we don't believe that this will cause ecosystem disruption.
  2. Rename the "inline" tag to something with no existing use in the ecosystem to avoid potential conflicts.
  3. Drop the "inline" tag entirely, and reconsider it for 1.28.
  4. Add a compatibility GODEBUG that gates the "inline" tag behind the language version. See the full description of this below.

cc @dsnet @aclements @ChrisHines @neild @liggitt

Activity

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

    FixPendingIssues that have a fix which has not yet been reviewed or submitted.release-blocker

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions