unlock unlimited code runs for $79, limited time →
NOSSLETTER.techLIVE
back to OSSpedia
api-designrefactoringerror-handling

code-generator: don't overwrite NegotiatedSerializer

Project: kubernetes/kubernetes | Language: Go | Concepts: api-design, refactoring, error-handling | Difficulty: junior
Link: https://github.com/kubernetes/kubernetes/pull/140317

The problem

When creating Kubernetes clientsets, the client configuration (rest.Config) always had its NegotiatedSerializer field overwritten, even if a non-nil value was already provided by the caller. This prevented consumers from customizing serialization logic, which is important for advanced use cases.

Why it's non-trivial

A naive fix might simply stop setting NegotiatedSerializer entirely, but that would break clients that rely on the default serializer being set up. The correct fix must only set a default if the field is not already set, preserving both custom and default behavior.

The approach

The core change is to only set NegotiatedSerializer if it is not already set. This pattern is repeated across all generated clientset setConfigDefaults functions.

Before:

-	config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion()

This line always overwrites NegotiatedSerializer, regardless of its current value.

After:

+	if config.NegotiatedSerializer == nil {
+		config.NegotiatedSerializer = rest.CodecFactoryForGeneratedClient(scheme.Scheme, scheme.Codecs).WithoutConversion()
+	}

This change checks if NegotiatedSerializer is nil before setting it. If the caller has already provided a serializer, it will be preserved. If not, the default is set as before.

This pattern is applied consistently across all affected files, ensuring uniform behavior for all generated clients.

From the review thread

No notable review discussion on this PR.

Takeaways

  • When setting default values in configuration structs, only set them if the field is unset to allow user overrides.
  • Consistency across generated or repeated code helps ensure predictable and debuggable behavior.
  • Preserving user-provided configuration values is important for extensibility and advanced use cases.