Congratulations!

[Valid Atom 1.0] This is a valid Atom 1.0 feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: http://blog.golang.org/feed.atom

  1. <feed xmlns="http://www.w3.org/2005/Atom"><title>The Go Blog</title><id>tag:blog.golang.org,2013:blog.golang.org</id><link rel="self" href="https://go.dev/blog/feed.atom"></link><updated>2025-09-16T00:00:00+00:00</updated><entry><title>It&#39;s survey time! How has Go has been working out for you?</title><id>tag:blog.golang.org,2013:blog.golang.org/survey2025-announce</id><link rel="alternate" href="https://go.dev/blog/survey2025-announce"></link><published>2025-09-16T00:00:00+00:00</published><updated>2025-09-16T00:00:00+00:00</updated><author><name>Todd Kulesza, on behalf of the Go team</name></author><summary type="html">Help shape the future of Go</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/survey2025-announce&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;It&amp;#39;s survey time! How has Go has been working out for you?&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Todd Kulesza, on behalf of the Go team&lt;br&gt;&#xA;      16 September 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;Hi Gophers! Today we&amp;rsquo;re excited to announce our &lt;a href=&#34;https://google.qualtrics.com/jfe/form/SV_3wwSstC8vv4Ymkm?s=b&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;2025 Go Developer Survey&lt;/a&gt;. The Go Team uses the results of this annual survey to better understand the needs and concerns of Go developers across the world. Your feedback helps us brainstorm, plan, and prioritize work on Go.&lt;/p&gt;&#xA;&lt;p&gt;You can &lt;a href=&#34;https://google.qualtrics.com/jfe/form/SV_3wwSstC8vv4Ymkm?s=b&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;take the survey here&lt;/a&gt;. It will be open through &lt;strong&gt;September 30th&lt;/strong&gt;. The survey should take 10 – 20 minutes to complete, and every question is optional.&lt;/p&gt;&#xA;&lt;p&gt;We&amp;rsquo;ll share aggregated survey results on this blog in early November. This year we&amp;rsquo;ll also share the raw dataset of survey responses, so that the entire Go community can benefit from this knowledge and conduct your own analyses on the data. Similar to our approach with &lt;a href=&#34;/blog/gotelemetry&#34;&gt;Go Telemetry&lt;/a&gt;, we&amp;rsquo;re using an opt-in model: the survey will ask for your permission to include your responses in the dataset. If you don&amp;rsquo;t give us permission, your survey responses will not be shared.&lt;/p&gt;&#xA;&lt;p&gt;Please help us reach as many Go developers as possible! We love it when you share the survey with your colleagues, friends, and online communities. The more voices we hear, the better we can understand the diverse needs of Go developers everywhere.&lt;/p&gt;&#xA;&lt;p&gt;We&amp;rsquo;re looking forward to hearing your feedback!&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/jsonv2-exp&#34;&gt;A new experimental Go API for JSON&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>A new experimental Go API for JSON</title><id>tag:blog.golang.org,2013:blog.golang.org/jsonv2-exp</id><link rel="alternate" href="https://go.dev/blog/jsonv2-exp"></link><published>2025-09-09T00:00:00+00:00</published><updated>2025-09-09T00:00:00+00:00</updated><author><name>Joe Tsai, Daniel Martí, Johan Brandhorst-Satzkorn, Roger Peppe, Chris Hines, and Damien Neil</name></author><summary type="html">Go 1.25 introduces experimental support for encoding/json/jsontext and encoding/json/v2 packages.</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/jsonv2-exp&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;A new experimental Go API for JSON&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Joe Tsai, Daniel Martí, Johan Brandhorst-Satzkorn, Roger Peppe, Chris Hines,  and Damien Neil&lt;br&gt;&#xA;      9 September 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc8259&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;JavaScript Object Notation (JSON)&lt;/a&gt;&#xA;is a simple data interchange format. Almost 15 years ago,&#xA;we wrote about &lt;a href=&#34;/blog/json&#34;&gt;support for JSON in Go&lt;/a&gt;,&#xA;which introduced the ability to serialize and deserialize Go types to and from JSON data.&#xA;Since then, JSON has become the most popular data format used on the Internet.&#xA;It is widely read and written by Go programs,&#xA;and encoding/json now ranks as the 5th most imported Go package.&lt;/p&gt;&#xA;&lt;p&gt;Over time, packages evolve with the needs of their users,&#xA;and &lt;code&gt;encoding/json&lt;/code&gt; is no exception. This blog post is about Go 1.25’s new&#xA;experimental &lt;code&gt;encoding/json/v2&lt;/code&gt; and &lt;code&gt;encoding/json/jsontext&lt;/code&gt; packages,&#xA;which bring long-awaited improvements and fixes.&#xA;This post argues for a new major API version,&#xA;provides an overview of the new packages,&#xA;and explains how you can make use of it.&#xA;The experimental packages are not visible by default and&#xA;may undergo future API changes.&lt;/p&gt;&#xA;&lt;h2 id=&#34;problems-with-encodingjson&#34;&gt;Problems with &lt;code&gt;encoding/json&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Overall, &lt;code&gt;encoding/json&lt;/code&gt; has held up well.&#xA;The idea of marshaling and unmarshaling arbitrary Go types&#xA;with some default representation in JSON, combined with the ability to&#xA;customize the representation, has proven to be highly flexible.&#xA;However, in the years since its introduction,&#xA;various users have identified numerous shortcomings.&lt;/p&gt;&#xA;&lt;h3 id=&#34;behavior-flaws&#34;&gt;Behavior flaws&lt;/h3&gt;&#xA;&lt;p&gt;There are various behavioral flaws in &lt;code&gt;encoding/json&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Imprecise handling of JSON syntax&lt;/strong&gt;: Over the years, JSON has seen&#xA;increased standardization in order for programs to properly communicate.&#xA;Generally, decoders have become stricter at rejecting ambiguous inputs,&#xA;to reduce the chance that two implementations will have different&#xA;(successful) interpretations of a particular JSON value.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;encoding/json&lt;/code&gt; currently accepts invalid UTF-8,&#xA;whereas the latest Internet Standard (RFC 8259) requires valid UTF-8.&#xA;The default behavior should report an error in the presence of invalid UTF-8,&#xA;instead of introducing silent data corruption,&#xA;which may cause problems downstream.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;encoding/json&lt;/code&gt; currently accepts objects with duplicate member names.&#xA;RFC 8259 does not specify how to handle duplicate names,&#xA;so an implementation is free to choose an arbitrary value,&#xA;merge the values, discard the values, or report an error.&#xA;The presence of a duplicate name results in a JSON value&#xA;without a universally agreed upon meaning.&#xA;This could be &lt;a href=&#34;https://www.youtube.com/watch?v=avilmOcHKHE&amp;amp;t=1057s&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;exploited by attackers in security applications&lt;/a&gt;&#xA;and has been exploited before (as in &lt;a href=&#34;https://nvd.nist.gov/vuln/detail/CVE-2017-12635&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;CVE-2017-12635&lt;/a&gt;).&#xA;The default behavior should err on the side of safety and reject duplicate names.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Leaking nilness of slices and maps&lt;/strong&gt;: JSON is often used to communicate with&#xA;programs using JSON implementations that do not allow &lt;code&gt;null&lt;/code&gt; to be unmarshaled&#xA;into a data type expected to be a JSON array or object.&#xA;Since &lt;code&gt;encoding/json&lt;/code&gt; marshals a nil slice or map as a JSON &lt;code&gt;null&lt;/code&gt;,&#xA;this may lead to errors when unmarshaling by other implementations.&#xA;&lt;a href=&#34;/issue/63397#discussioncomment-7201222&#34;&gt;A survey&lt;/a&gt;&#xA;indicated that most Go users prefer that nil slices and maps&#xA;are marshaled as an empty JSON array or object by default.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Case-insensitive unmarshaling&lt;/strong&gt;: When unmarshaling, a JSON object member name&#xA;is resolved to a Go struct field name using a case-insensitive match.&#xA;This is a surprising default, a potential security vulnerability, and a performance limitation.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Inconsistent calling of methods&lt;/strong&gt;: Due to an implementation detail,&#xA;&lt;code&gt;MarshalJSON&lt;/code&gt; methods declared on a pointer receiver&#xA;are &lt;a href=&#34;/issue/22967&#34;&gt;inconsistently called by &lt;code&gt;encoding/json&lt;/code&gt;&lt;/a&gt;. While regarded as a bug,&#xA;this cannot be fixed as too many applications depend on the current behavior.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;api-deficiencies&#34;&gt;API deficiencies&lt;/h3&gt;&#xA;&lt;p&gt;The API of &lt;code&gt;encoding/json&lt;/code&gt; can be tricky or restrictive:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;It is difficult to correctly unmarshal from an &lt;code&gt;io.Reader&lt;/code&gt;.&#xA;Users often write &lt;code&gt;json.NewDecoder(r).Decode(v)&lt;/code&gt;,&#xA;which fails to reject trailing junk at the end of the input.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Options can be set on the &lt;code&gt;Encoder&lt;/code&gt; and &lt;code&gt;Decoder&lt;/code&gt; types,&#xA;but cannot be used with the &lt;code&gt;Marshal&lt;/code&gt; and &lt;code&gt;Unmarshal&lt;/code&gt; functions.&#xA;Similarly, types implementing the &lt;code&gt;Marshaler&lt;/code&gt; and &lt;code&gt;Unmarshaler&lt;/code&gt; interfaces&#xA;cannot make use of the options and there is no way to plumb options down the call stack.&#xA;For example, the &lt;code&gt;Decoder.DisallowUnknownFields&lt;/code&gt; option loses its effect&#xA;when calling a custom &lt;code&gt;UnmarshalJSON&lt;/code&gt; method.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The &lt;code&gt;Compact&lt;/code&gt;, &lt;code&gt;Indent&lt;/code&gt;, and &lt;code&gt;HTMLEscape&lt;/code&gt; functions write to a &lt;code&gt;bytes.Buffer&lt;/code&gt;&#xA;instead of something more flexible like a &lt;code&gt;[]byte&lt;/code&gt; or &lt;code&gt;io.Writer&lt;/code&gt;.&#xA;This limits the usability of those functions.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;performance-limitations&#34;&gt;Performance limitations&lt;/h3&gt;&#xA;&lt;p&gt;Setting aside internal implementation details,&#xA;the public API commits it to certain performance limitations:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;MarshalJSON&lt;/strong&gt;: The &lt;code&gt;MarshalJSON&lt;/code&gt; interface method forces the implementation&#xA;to allocate the returned &lt;code&gt;[]byte&lt;/code&gt;. Also, the semantics require that&#xA;&lt;code&gt;encoding/json&lt;/code&gt; verify that the result is valid JSON&#xA;and also to reformat it to match the specified indentation.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;UnmarshalJSON&lt;/strong&gt;: The &lt;code&gt;UnmarshalJSON&lt;/code&gt; interface method requires that&#xA;a complete JSON value be provided (without any trailing data).&#xA;This forces &lt;code&gt;encoding/json&lt;/code&gt; to parse the JSON value to be unmarshaled&#xA;in its entirety to determine where it ends before it can call &lt;code&gt;UnmarshalJSON&lt;/code&gt;.&#xA;Afterwards, the &lt;code&gt;UnmarshalJSON&lt;/code&gt; method itself must parse the provided JSON value again.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Lack of streaming&lt;/strong&gt;: Even though the &lt;code&gt;Encoder&lt;/code&gt; and &lt;code&gt;Decoder&lt;/code&gt; types operate&#xA;on an &lt;code&gt;io.Writer&lt;/code&gt; or &lt;code&gt;io.Reader&lt;/code&gt;, they buffer the entire JSON value in memory.&#xA;The &lt;code&gt;Decoder.Token&lt;/code&gt; method for reading individual tokens is allocation-heavy&#xA;and there is no corresponding API for writing tokens.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Furthermore, if the implementation of a &lt;code&gt;MarshalJSON&lt;/code&gt; or &lt;code&gt;UnmarshalJSON&lt;/code&gt; method&#xA;recursively calls the &lt;code&gt;Marshal&lt;/code&gt; or &lt;code&gt;Unmarshal&lt;/code&gt; function,&#xA;then the performance becomes quadratic.&lt;/p&gt;&#xA;&lt;h2 id=&#34;trying-to-fix-encodingjson-directly&#34;&gt;Trying to fix &lt;code&gt;encoding/json&lt;/code&gt; directly&lt;/h2&gt;&#xA;&lt;p&gt;Introducing a new, incompatible major version of a package is a heavy consideration.&#xA;If possible, we should try to fix the existing package.&lt;/p&gt;&#xA;&lt;p&gt;While it is relatively easy to add new features,&#xA;it is difficult to change existing features.&#xA;Unfortunately, these problems are inherent consequences of the existing API,&#xA;making them practically impossible to fix within the &lt;a href=&#34;/doc/go1compat&#34;&gt;Go 1 compatibility promise&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;We could in principle declare separate names, such as &lt;code&gt;MarshalV2&lt;/code&gt; or &lt;code&gt;UnmarshalV2&lt;/code&gt;,&#xA;but that is tantamount to creating a parallel namespace within the same package.&#xA;This leads us to &lt;code&gt;encoding/json/v2&lt;/code&gt; (henceforth called &lt;code&gt;v2&lt;/code&gt;),&#xA;where we can make these changes within a separate &lt;code&gt;v2&lt;/code&gt; namespace&#xA;in contrast to &lt;code&gt;encoding/json&lt;/code&gt; (henceforth called &lt;code&gt;v1&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;h2 id=&#34;planning-for-encodingjsonv2&#34;&gt;Planning for &lt;code&gt;encoding/json/v2&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The planning for a new major version of &lt;code&gt;encoding/json&lt;/code&gt; spanned years.&#xA;In late 2020, spurred on by the inability to fix issues in the current package,&#xA;Daniel Martí (one of the maintainers of &lt;code&gt;encoding/json&lt;/code&gt;) first drafted his&#xA;thoughts on &lt;a href=&#34;https://docs.google.com/document/d/1WQGoM44HLinH4NGBEv5drGlw5_RNW-GP7DdGEpm7Y3o&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;what a hypothetical &lt;code&gt;v2&lt;/code&gt; package should look like&lt;/a&gt;.&#xA;Separately, after previous work on the &lt;a href=&#34;/blog/protobuf-apiv2&#34;&gt;Go API for Protocol Buffers&lt;/a&gt;,&#xA;Joe Tsai was disapppointed that &lt;a href=&#34;/pkg/google.golang.org/protobuf/encoding/protojson&#34;&gt;the &lt;code&gt;protojson&lt;/code&gt; package&lt;/a&gt;&#xA;needed to use a custom JSON implementation because &lt;code&gt;encoding/json&lt;/code&gt; was&#xA;neither capable of adhering to the stricter JSON standard that the&#xA;Protocol Buffer specification required,&#xA;nor of efficiently serializing JSON in a streaming manner.&lt;/p&gt;&#xA;&lt;p&gt;Believing a brighter future for JSON was both beneficial and achievable,&#xA;Daniel and Joe joined forces to brainstorm on &lt;code&gt;v2&lt;/code&gt; and&#xA;&lt;a href=&#34;https://github.com/go-json-experiment/json&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;started to build a prototype&lt;/a&gt;&#xA;(with the initial code being a polished version of the JSON serialization logic from the Go protobuf module).&#xA;Over time, a few others (Roger Peppe, Chris Hines, Johan Brandhorst-Satzkorn, and Damien Neil)&#xA;joined the effort by providing design review, code review, and regression testing.&#xA;Many of the early discussions are publicly available in our&#xA;&lt;a href=&#34;https://www.youtube.com/playlist?list=PLZgrQPcV8W8EChkaAvv-3NUu6PYmnGG3b&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;recorded meetings&lt;/a&gt; and&#xA;&lt;a href=&#34;https://docs.google.com/document/d/1rovrOTd-wTawGMPPlPuKhwXaYBg9VszTXR9AQQL5LfI&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;meeting notes&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This work has been public since the beginning,&#xA;and we increasingly involved the wider Go community,&#xA;first with a&#xA;&lt;a href=&#34;https://www.youtube.com/watch?v=avilmOcHKHE&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;GopherCon talk&lt;/a&gt; and&#xA;&lt;a href=&#34;/issue/63397&#34;&gt;discussion posted in late 2023&lt;/a&gt;,&#xA;&lt;a href=&#34;/issue/71497&#34;&gt;formal proposal posted in early 2025&lt;/a&gt;,&#xA;and most recently &lt;a href=&#34;/issue/71845&#34;&gt;adopting &lt;code&gt;encoding/json/v2&lt;/code&gt; as a Go experiment&lt;/a&gt;&#xA;(available in Go 1.25) for wider-scale testing by all Go users.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;v2&lt;/code&gt; effort has been going on for 5 years,&#xA;incorporating feedback from many contributors and also gaining valuable&#xA;empirical experience from use in production settings.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s worth noting that it&amp;rsquo;s largely been developed and promoted by people&#xA;not employed by Google, demonstrating that the Go project is a collaborative endeavor&#xA;with a thriving global community dedicated to improving the Go ecosystem.&lt;/p&gt;&#xA;&lt;h2 id=&#34;building-on-encodingjsonjsontext&#34;&gt;Building on &lt;code&gt;encoding/json/jsontext&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Before discussing the &lt;code&gt;v2&lt;/code&gt; API, we first introduce the experimental&#xA;&lt;a href=&#34;/pkg/encoding/json/jsontext&#34;&gt;&lt;code&gt;encoding/json/jsontext&lt;/code&gt;&lt;/a&gt; package&#xA;that lays the foundation for future improvements to JSON in Go.&lt;/p&gt;&#xA;&lt;p&gt;JSON serialization in Go can be broken down into two primary components:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;em&gt;syntactic functionality&lt;/em&gt; that is concerned with processing JSON based on its grammar, and&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;semantic functionality&lt;/em&gt; that defines the relationship between JSON values and Go values.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;We use the terms &amp;ldquo;encode&amp;rdquo; and &amp;ldquo;decode&amp;rdquo; to describe syntactic functionality and&#xA;the terms &amp;ldquo;marshal&amp;rdquo; and &amp;ldquo;unmarshal&amp;rdquo; to describe semantic functionality.&#xA;We aim to provide a clear distinction between functionality&#xA;that is purely concerned with encoding versus that of marshaling.&lt;/p&gt;&#xA;&lt;img src=&#34;jsonv2-exp/api.png&#34; width=100%&gt;&#xA;&lt;p&gt;This diagram provides an overview of this separation.&#xA;Purple blocks represent types, while blue blocks represent functions or methods.&#xA;The direction of the arrows approximately represents the flow of data.&#xA;The bottom half of the diagram, implemented by the &lt;code&gt;jsontext&lt;/code&gt; package,&#xA;contains functionality that is only concerned with syntax,&#xA;while the upper half, implemented by the &lt;code&gt;json/v2&lt;/code&gt; package,&#xA;contains functionality that assigns semantic meaning to syntactic data&#xA;handled by the bottom half.&lt;/p&gt;&#xA;&lt;p&gt;The basic API of &lt;code&gt;jsontext&lt;/code&gt; is the following:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;package jsontext&#xA;&#xA;type Encoder struct { ... }&#xA;func NewEncoder(io.Writer, ...Options) *Encoder&#xA;func (*Encoder) WriteValue(Value) error&#xA;func (*Encoder) WriteToken(Token) error&#xA;&#xA;type Decoder struct { ... }&#xA;func NewDecoder(io.Reader, ...Options) *Decoder&#xA;func (*Decoder) ReadValue() (Value, error)&#xA;func (*Decoder) ReadToken() (Token, error)&#xA;&#xA;type Kind byte&#xA;type Value []byte&#xA;func (Value) Kind() Kind&#xA;type Token struct { ... }&#xA;func (Token) Kind() Kind&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;code&gt;jsontext&lt;/code&gt; package provides functionality for interacting with JSON&#xA;at a syntactic level and derives its name from&#xA;&lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc8259#section-2&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;RFC 8259, section 2&lt;/a&gt;&#xA;where the grammar for JSON data is literally called &lt;code&gt;JSON-text&lt;/code&gt;.&#xA;Since it only interacts with JSON at a syntactic level,&#xA;it does not depend on Go reflection.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;/pkg/encoding/json/jsontext#Encoder&#34;&gt;&lt;code&gt;Encoder&lt;/code&gt;&lt;/a&gt; and&#xA;&lt;a href=&#34;/pkg/encoding/json/jsontext#Decoder&#34;&gt;&lt;code&gt;Decoder&lt;/code&gt;&lt;/a&gt;&#xA;provide support for encoding and decoding JSON values and tokens.&#xA;The constructors&#xA;&lt;a href=&#34;/pkg/encoding/json/jsontext#Options&#34;&gt;accept variadic options&lt;/a&gt;&#xA;that affect the particular behavior of encoding and decoding.&#xA;Unlike the &lt;code&gt;Encoder&lt;/code&gt; and &lt;code&gt;Decoder&lt;/code&gt; types declared in &lt;code&gt;v1&lt;/code&gt;,&#xA;the new types in &lt;code&gt;jsontext&lt;/code&gt; avoid muddling the distinction between syntax and&#xA;semantics and operate in a truly streaming manner.&lt;/p&gt;&#xA;&lt;p&gt;A JSON value is a complete unit of data and is represented in Go as&#xA;&lt;a href=&#34;/pkg/encoding/json/jsontext#Value&#34;&gt;a named &lt;code&gt;[]byte&lt;/code&gt;&lt;/a&gt;.&#xA;It is identical to &lt;a href=&#34;/pkg/encoding/json#RawMessage&#34;&gt;&lt;code&gt;RawMessage&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;v1&lt;/code&gt;.&#xA;A JSON value is syntactically composed of one or more JSON tokens.&#xA;A JSON token is represented in Go as the &lt;a href=&#34;/pkg/encoding/json/jsontext#Token&#34;&gt;opaque &lt;code&gt;Token&lt;/code&gt; type&lt;/a&gt;&#xA;with constructors and accessor methods.&#xA;It is analogous to &lt;a href=&#34;/pkg/encoding/json#Token&#34;&gt;&lt;code&gt;Token&lt;/code&gt;&lt;/a&gt; in &lt;code&gt;v1&lt;/code&gt;&#xA;but is designed represent arbitrary JSON tokens without allocation.&lt;/p&gt;&#xA;&lt;p&gt;To resolve the fundamental performance problems with&#xA;the &lt;code&gt;MarshalJSON&lt;/code&gt; and &lt;code&gt;UnmarshalJSON&lt;/code&gt; interface methods,&#xA;we need an efficient way of encoding and decoding JSON&#xA;as a streaming sequence of tokens and values.&#xA;In &lt;code&gt;v2&lt;/code&gt;, we introduce the &lt;code&gt;MarshalJSONTo&lt;/code&gt; and &lt;code&gt;UnmarshalJSONFrom&lt;/code&gt; interface methods&#xA;that operate on an &lt;code&gt;Encoder&lt;/code&gt; or &lt;code&gt;Decoder&lt;/code&gt;, allowing the methods&amp;rsquo; implementations&#xA;to process JSON in a purely streaming manner. Thus, the &lt;code&gt;json&lt;/code&gt; package need not&#xA;be responsible for validating or formatting a JSON value returned by &lt;code&gt;MarshalJSON&lt;/code&gt;,&#xA;nor would it need to be responsible for determining the boundaries of a JSON value&#xA;provided to &lt;code&gt;UnmarshalJSON&lt;/code&gt;. These responsibilities belong to the &lt;code&gt;Encoder&lt;/code&gt; and &lt;code&gt;Decoder&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introducing-encodingjsonv2&#34;&gt;Introducing &lt;code&gt;encoding/json/v2&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Building on the &lt;code&gt;jsontext&lt;/code&gt; package, we now introduce the experimental&#xA;&lt;a href=&#34;/pkg/encoding/json/v2&#34;&gt;&lt;code&gt;encoding/json/v2&lt;/code&gt;&lt;/a&gt; package.&#xA;It is designed to fix the aforementioned problems,&#xA;while remaining familiar to users of the &lt;code&gt;v1&lt;/code&gt; package.&#xA;Our goal is that usages of &lt;code&gt;v1&lt;/code&gt; will operate &lt;em&gt;mostly&lt;/em&gt; the same if directly migrated to &lt;code&gt;v2&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;In this article, we will primarily cover the high-level API of &lt;code&gt;v2&lt;/code&gt;.&#xA;For examples on how to use it, we encourage readers to&#xA;study &lt;a href=&#34;/pkg/encoding/json/v2#pkg-examples&#34;&gt;the examples in the &lt;code&gt;v2&lt;/code&gt; package&lt;/a&gt; or&#xA;read &lt;a href=&#34;https://antonz.org/go-json-v2/&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Anton Zhiyanov&amp;rsquo;s blog covering the topic&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The basic API of &lt;code&gt;v2&lt;/code&gt; is the following:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;package json&#xA;&#xA;func Marshal(in any, opts ...Options) (out []byte, err error)&#xA;func MarshalWrite(out io.Writer, in any, opts ...Options) error&#xA;func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) error&#xA;&#xA;func Unmarshal(in []byte, out any, opts ...Options) error&#xA;func UnmarshalRead(in io.Reader, out any, opts ...Options) error&#xA;func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) error&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;/pkg/encoding/json/v2#Marshal&#34;&gt;&lt;code&gt;Marshal&lt;/code&gt;&lt;/a&gt;&#xA;and &lt;a href=&#34;/pkg/encoding/json/v2#Unmarshal&#34;&gt;&lt;code&gt;Unmarshal&lt;/code&gt;&lt;/a&gt; functions&#xA;have a signature similar to &lt;code&gt;v1&lt;/code&gt;, but accept options to configure their behavior.&#xA;The &lt;a href=&#34;/pkg/encoding/json/v2#MarshalWrite&#34;&gt;&lt;code&gt;MarshalWrite&lt;/code&gt;&lt;/a&gt;&#xA;and &lt;a href=&#34;/pkg/encoding/json/v2#UnmarshalRead&#34;&gt;&lt;code&gt;UnmarshalRead&lt;/code&gt;&lt;/a&gt; functions&#xA;directly operate on an &lt;code&gt;io.Writer&lt;/code&gt; or &lt;code&gt;io.Reader&lt;/code&gt;,&#xA;avoiding the need to temporarily construct an &lt;code&gt;Encoder&lt;/code&gt; or &lt;code&gt;Decoder&lt;/code&gt;&#xA;just to write or read from such types.&#xA;The &lt;a href=&#34;/pkg/encoding/json/v2#MarshalEncode&#34;&gt;&lt;code&gt;MarshalEncode&lt;/code&gt;&lt;/a&gt;&#xA;and &lt;a href=&#34;/pkg/encoding/json/v2#UnmarshalDecode&#34;&gt;&lt;code&gt;UnmarshalDecode&lt;/code&gt;&lt;/a&gt; functions&#xA;operate on a &lt;code&gt;jsontext.Encoder&lt;/code&gt; and &lt;code&gt;jsontext.Decoder&lt;/code&gt; and&#xA;is actually the underlying implementation of the previously mentioned functions.&#xA;Unlike &lt;code&gt;v1&lt;/code&gt;, options are a first-class argument to each of the marshal and unmarshal functions,&#xA;greatly extending the flexibility and configurability of &lt;code&gt;v2&lt;/code&gt;.&#xA;There are &lt;a href=&#34;/pkg/encoding/json/v2#Options&#34;&gt;several options available&lt;/a&gt;&#xA;in &lt;code&gt;v2&lt;/code&gt; which are not covered by this article.&lt;/p&gt;&#xA;&lt;h3 id=&#34;type-specified-customization&#34;&gt;Type-specified customization&lt;/h3&gt;&#xA;&lt;p&gt;Similar to &lt;code&gt;v1&lt;/code&gt;, &lt;code&gt;v2&lt;/code&gt; allows types to define their own JSON representation&#xA;by satisfying particular interfaces.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type Marshaler interface {&#xA;    MarshalJSON() ([]byte, error)&#xA;}&#xA;type MarshalerTo interface {&#xA;    MarshalJSONTo(*jsontext.Encoder) error&#xA;}&#xA;&#xA;type Unmarshaler interface {&#xA;    UnmarshalJSON([]byte) error&#xA;}&#xA;type UnmarshalerFrom interface {&#xA;    UnmarshalJSONFrom(*jsontext.Decoder) error&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;/pkg/encoding/json/v2#Marshaler&#34;&gt;&lt;code&gt;Marshaler&lt;/code&gt;&lt;/a&gt;&#xA;and &lt;a href=&#34;/pkg/encoding/json/v2#Unmarshaler&#34;&gt;&lt;code&gt;Unmarshaler&lt;/code&gt;&lt;/a&gt; interfaces&#xA;are identical to those in &lt;code&gt;v1&lt;/code&gt;.&#xA;The new &lt;a href=&#34;/pkg/encoding/json/v2#MarshalerTo&#34;&gt;&lt;code&gt;MarshalerTo&lt;/code&gt;&lt;/a&gt;&#xA;and &lt;a href=&#34;/pkg/encoding/json/v2#UnmarshalerFrom&#34;&gt;&lt;code&gt;UnmarshalerFrom&lt;/code&gt;&lt;/a&gt; interfaces&#xA;allow a type to represent itself as JSON using a &lt;code&gt;jsontext.Encoder&lt;/code&gt; or &lt;code&gt;jsontext.Decoder&lt;/code&gt;.&#xA;This allows options to be forwarded down the call stack, since options&#xA;can be retrieved via the &lt;code&gt;Options&lt;/code&gt; accessor method on the &lt;code&gt;Encoder&lt;/code&gt; or &lt;code&gt;Decoder&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;See &lt;a href=&#34;/pkg/encoding/json/v2#example-package-OrderedObject&#34;&gt;the &lt;code&gt;OrderedObject&lt;/code&gt; example&lt;/a&gt;&#xA;for how to implement a custom type that maintains the ordering of JSON object members.&lt;/p&gt;&#xA;&lt;h3 id=&#34;caller-specified-customization&#34;&gt;Caller-specified customization&lt;/h3&gt;&#xA;&lt;p&gt;In &lt;code&gt;v2&lt;/code&gt;, the caller of &lt;code&gt;Marshal&lt;/code&gt; and &lt;code&gt;Unmarshal&lt;/code&gt; can also specify&#xA;a custom JSON representation for any arbitrary type,&#xA;where caller-specified functions take precedence over type-defined methods&#xA;or the default representation for a particular type.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func WithMarshalers(*Marshalers) Options&#xA;&#xA;type Marshalers struct { ... }&#xA;func MarshalFunc[T any](fn func(T) ([]byte, error)) *Marshalers&#xA;func MarshalToFunc[T any](fn func(*jsontext.Encoder, T) error) *Marshalers&#xA;&#xA;func WithUnmarshalers(*Unmarshalers) Options&#xA;&#xA;type Unmarshalers struct { ... }&#xA;func UnmarshalFunc[T any](fn func([]byte, T) error) *Unmarshalers&#xA;func UnmarshalFromFunc[T any](fn func(*jsontext.Decoder, T) error) *Unmarshalers&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;a href=&#34;/pkg/encoding/json/v2#MarshalFunc&#34;&gt;&lt;code&gt;MarshalFunc&lt;/code&gt;&lt;/a&gt; and&#xA;&lt;a href=&#34;/pkg/encoding/json/v2#MarshalToFunc&#34;&gt;&lt;code&gt;MarshalToFunc&lt;/code&gt;&lt;/a&gt;&#xA;construct a custom marshaler that can be passed to a &lt;code&gt;Marshal&lt;/code&gt; call&#xA;using &lt;code&gt;WithMarshalers&lt;/code&gt; to override the marshaling of particular types.&#xA;Similarly,&#xA;&lt;a href=&#34;/pkg/encoding/json/v2#UnmarshalFunc&#34;&gt;&lt;code&gt;UnmarshalFunc&lt;/code&gt;&lt;/a&gt; and&#xA;&lt;a href=&#34;/pkg/encoding/json/v2#UnmarshalFromFunc&#34;&gt;&lt;code&gt;UnmarshalFromFunc&lt;/code&gt;&lt;/a&gt;&#xA;support similar customization for &lt;code&gt;Unmarshal&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;/pkg/encoding/json/v2#example-package-ProtoJSON&#34;&gt;The &lt;code&gt;ProtoJSON&lt;/code&gt; example&lt;/a&gt;&#xA;demonstrates how this feature allows serialization of all&#xA;&lt;a href=&#34;/pkg/google.golang.org/protobuf/proto#Message&#34;&gt;&lt;code&gt;proto.Message&lt;/code&gt;&lt;/a&gt; types&#xA;to be handled by the &lt;a href=&#34;/pkg/google.golang.org/protobuf/encoding/protojson&#34;&gt;&lt;code&gt;protojson&lt;/code&gt;&lt;/a&gt; package.&lt;/p&gt;&#xA;&lt;h3 id=&#34;behavior-differences&#34;&gt;Behavior differences&lt;/h3&gt;&#xA;&lt;p&gt;While &lt;code&gt;v2&lt;/code&gt; aims to behave &lt;em&gt;mostly&lt;/em&gt; the same as &lt;code&gt;v1&lt;/code&gt;,&#xA;its behavior has changed &lt;a href=&#34;/pkg/github.com/go-json-experiment/json/v1#hdr-Migrating_to_v2&#34;&gt;in some ways&lt;/a&gt;&#xA;to address problems in &lt;code&gt;v1&lt;/code&gt;, most notably:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;v2&lt;/code&gt; reports an error in the presence of invalid UTF-8.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;v2&lt;/code&gt; reports an error if a JSON object contains a duplicate name.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;v2&lt;/code&gt; marshals a nil Go slice or Go map as an empty JSON array or JSON object, respectively.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;v2&lt;/code&gt; unmarshals a JSON object into a Go struct using a&#xA;case-sensitive match from the JSON member name to the Go field name.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;v2&lt;/code&gt; redefines the &lt;code&gt;omitempty&lt;/code&gt; tag option to omit a field if it would have&#xA;encoded as an &amp;ldquo;empty&amp;rdquo; JSON value (which are &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;, &lt;code&gt;[]&lt;/code&gt;, and &lt;code&gt;{}&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;v2&lt;/code&gt; reports an error when trying to serialize a &lt;code&gt;time.Duration&lt;/code&gt;,&#xA;which currently has &lt;a href=&#34;/issue/71631&#34;&gt;no default representation&lt;/a&gt;,&#xA;but provides options to let the caller decide.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;For most behavior changes, there is a struct tag option or caller-specified option&#xA;that can configure the behavior to operate under &lt;code&gt;v1&lt;/code&gt; or &lt;code&gt;v2&lt;/code&gt; semantics,&#xA;or even other caller-determined behavior.&#xA;See &lt;a href=&#34;/pkg/github.com/go-json-experiment/json/v1#hdr-Migrating_to_v2&#34;&gt;&amp;ldquo;Migrating to v2&amp;rdquo;&lt;/a&gt; for more information.&lt;/p&gt;&#xA;&lt;h3 id=&#34;performance-optimizations&#34;&gt;Performance optimizations&lt;/h3&gt;&#xA;&lt;p&gt;The &lt;code&gt;Marshal&lt;/code&gt; performance of &lt;code&gt;v2&lt;/code&gt; is roughly at parity with &lt;code&gt;v1&lt;/code&gt;.&#xA;Sometimes it is slightly faster, but other times it is slightly slower.&#xA;The &lt;code&gt;Unmarshal&lt;/code&gt; performance of &lt;code&gt;v2&lt;/code&gt; is significantly faster than &lt;code&gt;v1&lt;/code&gt;,&#xA;with benchmarks demonstrating improvements of up to 10x.&lt;/p&gt;&#xA;&lt;p&gt;In order to obtain greater performance gains,&#xA;existing implementations of&#xA;&lt;a href=&#34;/pkg/encoding/json/v2#Marshaler&#34;&gt;&lt;code&gt;Marshaler&lt;/code&gt;&lt;/a&gt; and&#xA;&lt;a href=&#34;/pkg/encoding/json/v2#Unmarshaler&#34;&gt;&lt;code&gt;Unmarshaler&lt;/code&gt;&lt;/a&gt; should&#xA;migrate to also implement&#xA;&lt;a href=&#34;/pkg/encoding/json/v2#MarshalerTo&#34;&gt;&lt;code&gt;MarshalerTo&lt;/code&gt;&lt;/a&gt; and&#xA;&lt;a href=&#34;/pkg/encoding/json/v2#UnmarshalerFrom&#34;&gt;&lt;code&gt;UnmarshalerFrom&lt;/code&gt;&lt;/a&gt;,&#xA;so that they can benefit from processing JSON in a purely streaming manner.&#xA;For example, recursive parsing of OpenAPI specifications in &lt;code&gt;UnmarshalJSON&lt;/code&gt; methods&#xA;significantly hurt performance in a particular service of Kubernetes&#xA;(see &lt;a href=&#34;https://github.com/kubernetes/kube-openapi/issues/315&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;kubernetes/kube-openapi#315&lt;/a&gt;),&#xA;while switching to &lt;code&gt;UnmarshalJSONFrom&lt;/code&gt; improved performance by orders of magnitude.&lt;/p&gt;&#xA;&lt;p&gt;For more information, see the&#xA;&lt;a href=&#34;https://github.com/go-json-experiment/jsonbench&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;go-json-experiment/jsonbench&lt;/code&gt;&lt;/a&gt;&#xA;repository.&lt;/p&gt;&#xA;&lt;h2 id=&#34;retroactively-improving-encodingjson&#34;&gt;Retroactively improving &lt;code&gt;encoding/json&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;We want to avoid two separate JSON implementations in the Go standard library,&#xA;so it is critical that, under the hood, &lt;code&gt;v1&lt;/code&gt; is implemented in terms of &lt;code&gt;v2&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;There are several benefits to this approach:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Gradual migration&lt;/strong&gt;: The &lt;code&gt;Marshal&lt;/code&gt; and &lt;code&gt;Unmarshal&lt;/code&gt; functions in &lt;code&gt;v1&lt;/code&gt; or &lt;code&gt;v2&lt;/code&gt;&#xA;represent a set of default behaviors that operate according to &lt;code&gt;v1&lt;/code&gt; or &lt;code&gt;v2&lt;/code&gt; semantics.&#xA;Options can be specified that configure &lt;code&gt;Marshal&lt;/code&gt; or &lt;code&gt;Unmarshal&lt;/code&gt; to operate with&#xA;entirely &lt;code&gt;v1&lt;/code&gt;, mostly &lt;code&gt;v1&lt;/code&gt; with a some &lt;code&gt;v2&lt;/code&gt;, a mix of &lt;code&gt;v1&lt;/code&gt; or &lt;code&gt;v2&lt;/code&gt;,&#xA;mostly &lt;code&gt;v2&lt;/code&gt; with some &lt;code&gt;v1&lt;/code&gt;, or entirely &lt;code&gt;v2&lt;/code&gt; semantics.&#xA;This allows for gradual migration between the default behaviors of the two versions.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Feature inheritance&lt;/strong&gt;: As backward-compatible features are added to &lt;code&gt;v2&lt;/code&gt;,&#xA;they will inherently be made available in &lt;code&gt;v1&lt;/code&gt;. For example, &lt;code&gt;v2&lt;/code&gt; adds&#xA;support for several new struct tag options such as &lt;code&gt;inline&lt;/code&gt; or &lt;code&gt;format&lt;/code&gt; and also&#xA;support for the &lt;code&gt;MarshalJSONTo&lt;/code&gt; and &lt;code&gt;UnmarshalJSONFrom&lt;/code&gt; interface methods,&#xA;which are both more performant and flexible.&#xA;When &lt;code&gt;v1&lt;/code&gt; is implemented in terms of &lt;code&gt;v2&lt;/code&gt;, it will inherit support for these features.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Reduced maintenance&lt;/strong&gt;: Maintenance of a widely used package demands significant effort.&#xA;By having &lt;code&gt;v1&lt;/code&gt; and &lt;code&gt;v2&lt;/code&gt; use the same implementation, the maintenance burden is reduced.&#xA;In general, a single change will fix bugs, improve performance, or add functionality to both versions.&#xA;There is no need to backport a &lt;code&gt;v2&lt;/code&gt; change with an equivalent &lt;code&gt;v1&lt;/code&gt; change.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;While select parts of &lt;code&gt;v1&lt;/code&gt; may be deprecated over time (supposing &lt;code&gt;v2&lt;/code&gt; graduates from being an experiment),&#xA;the package as a whole will never be deprecated.&#xA;Migrating to &lt;code&gt;v2&lt;/code&gt; will be encouraged, but not required.&#xA;The Go project will not drop support for &lt;code&gt;v1&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;experimenting-with-jsonv2&#34;&gt;Experimenting with &lt;code&gt;jsonv2&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The newer API in the &lt;code&gt;encoding/json/jsontext&lt;/code&gt; and &lt;code&gt;encoding/json/v2&lt;/code&gt; packages are not visible by default.&#xA;To use them, build your code with &lt;code&gt;GOEXPERIMENT=jsonv2&lt;/code&gt; set in your environment or with the &lt;code&gt;goexperiment.jsonv2&lt;/code&gt; build tag.&#xA;The nature of an experiment is that the API is unstable and may change in the future.&#xA;Though the API is unstable, the implementation is of a high quality and&#xA;has been successfully used in production by several major projects.&lt;/p&gt;&#xA;&lt;p&gt;The fact that &lt;code&gt;v1&lt;/code&gt; is implemented in terms of &lt;code&gt;v2&lt;/code&gt; means that the underlying implementation of &lt;code&gt;v1&lt;/code&gt;&#xA;is completely different when building under the &lt;code&gt;jsonv2&lt;/code&gt; experiment.&#xA;Without changing any code, you should be able to run your tests&#xA;under &lt;code&gt;jsonv2&lt;/code&gt; and theoretically nothing new should fail:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;GOEXPERIMENT=jsonv2 go test ./...&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The re-implementation of &lt;code&gt;v1&lt;/code&gt; in terms of &lt;code&gt;v2&lt;/code&gt; aims to provide identical behavior&#xA;within the bounds of the &lt;a href=&#34;/doc/go1compat&#34;&gt;Go 1 compatibility promise&lt;/a&gt;,&#xA;though some differences might be observable such as the exact wording of error messages.&#xA;We encourage you to run your tests under &lt;code&gt;jsonv2&lt;/code&gt; and&#xA;report any regressions &lt;a href=&#34;/issues&#34;&gt;on the issue tracker&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Becoming an experiment in Go 1.25 is a significant milestone on the road to&#xA;formally adopting &lt;code&gt;encoding/json/jsontext&lt;/code&gt; and &lt;code&gt;encoding/json/v2&lt;/code&gt; into the standard library.&#xA;However, the purpose of the &lt;code&gt;jsonv2&lt;/code&gt; experiment is to gain broader experience.&#xA;Your feedback will determine our next steps, and the outcome of this experiment,&#xA;which may result in anything from abandonment of the effort, to adoption as stable packages of Go 1.26.&#xA;Please share your experience on &lt;a href=&#34;/issue/71497&#34;&gt;go.dev/issue/71497&lt;/a&gt;, and help determine the future of Go.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/survey2025-announce&#34;&gt;It&amp;#39;s survey time! How has Go has been working out for you?&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/testing-time&#34;&gt;Testing Time (and other asynchronicities)&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>Testing Time (and other asynchronicities)</title><id>tag:blog.golang.org,2013:blog.golang.org/testing-time</id><link rel="alternate" href="https://go.dev/blog/testing-time"></link><published>2025-08-26T00:00:00+00:00</published><updated>2025-08-26T00:00:00+00:00</updated><author><name>Damien Neil</name></author><summary type="html">A discussion of testing asyncronous code and an exploration of the `testing/synctest` package. Based on the GopherCon Europe 2025 talk with the same title.</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/testing-time&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;Testing Time (and other asynchronicities)&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Damien Neil&lt;br&gt;&#xA;      26 August 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;In Go 1.24, we introduced the &lt;a href=&#34;/pkg/testing/synctest&#34;&gt;&lt;code&gt;testing/synctest&lt;/code&gt;&lt;/a&gt;&#xA;package as an experimental package.&#xA;This package can significantly simplify writing tests for concurrent,&#xA;asynchronous code.&#xA;In Go 1.25, the &lt;code&gt;testing/synctest&lt;/code&gt; package has graduated from experiment&#xA;to general availability.&lt;/p&gt;&#xA;&lt;p&gt;What follows is the blog version of my talk on&#xA;the &lt;a href=&#34;/pkg/testing/synctest&#34;&gt;&lt;code&gt;testing/synctest&lt;/code&gt;&lt;/a&gt; package&#xA;at GopherCon Europe 2025 in Berlin.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-an-asynchronous-function&#34;&gt;What is an asynchronous function?&lt;/h2&gt;&#xA;&lt;p&gt;A synchronous function is pretty simple.&#xA;You call it, it does something, and it returns.&lt;/p&gt;&#xA;&lt;p&gt;An asynchronous function is different.&#xA;You call it, it returns, and then it does something.&lt;/p&gt;&#xA;&lt;p&gt;As a concrete, if somewhat artificial, example,&#xA;the following &lt;code&gt;Cleanup&lt;/code&gt; function is synchronous.&#xA;You call it, it deletes a cache directory, and it returns.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func (c *Cache) Cleanup() {&#xA;    os.RemoveAll(c.cacheDir)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;CleanupInBackground&lt;/code&gt; is an asynchronous function.&#xA;You call it, it returns, and the cache directory is deleted&amp;hellip;sooner or later.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func (c *Cache) CleanupInBackground() {&#xA;    go os.RemoveAll(c.cacheDir)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Sometimes an asynchronous function does something in the future.&#xA;For example, the &lt;code&gt;context&lt;/code&gt; package&amp;rsquo;s &lt;code&gt;WithDeadline&lt;/code&gt; function&#xA;returns a context which will be canceled in the future.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;package context&#xA;&#xA;// WithDeadline returns a derived context&#xA;// with a deadline no later than d.&#xA;func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;When I talk about testing concurrent code,&#xA;I mean testing these sorts of asynchronous operations,&#xA;both ones which use real time and ones which do not.&lt;/p&gt;&#xA;&lt;h2 id=&#34;tests&#34;&gt;Tests&lt;/h2&gt;&#xA;&lt;p&gt;A test verifies that a system behaves as we expect.&#xA;There&amp;rsquo;s a lot of terminology describing types&#xA;of test&amp;ndash;unit tests, integration tests, and so on&amp;ndash;but&#xA;for our purposes here every kind of test reduces to three steps:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Set up some initial conditions.&lt;/li&gt;&#xA;&lt;li&gt;Tell the system under test to do something.&lt;/li&gt;&#xA;&lt;li&gt;Verify the result.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Testing a synchronous function is straightforward:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;You call the function;&lt;/li&gt;&#xA;&lt;li&gt;the function does something and returns;&lt;/li&gt;&#xA;&lt;li&gt;you verify the result.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Testing an asyncronous function, however, is tricky:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;You call the function;&lt;/li&gt;&#xA;&lt;li&gt;it returns;&lt;/li&gt;&#xA;&lt;li&gt;you wait for it to finish doing whatever it does;&lt;/li&gt;&#xA;&lt;li&gt;you verify the result.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;If you don&amp;rsquo;t wait for the correct amount of time,&#xA;you may find yourself verifying the result of an operation that hasn&amp;rsquo;t happened yet&#xA;or has only happened partially.&#xA;This never ends well.&lt;/p&gt;&#xA;&lt;p&gt;Testing an asynchronous function is especially tricky&#xA;when you want to assert that something has &lt;em&gt;not&lt;/em&gt; happened.&#xA;You can verify that the thing has not happened yet,&#xA;but how do you know with certainty that it isn&amp;rsquo;t going to happen later?&lt;/p&gt;&#xA;&lt;h2 id=&#34;an-example&#34;&gt;An example&lt;/h2&gt;&#xA;&lt;p&gt;To make things a little more concrete,&#xA;let&amp;rsquo;s work with a real-world example.&#xA;Consider the &lt;code&gt;context&lt;/code&gt; package&amp;rsquo;s &lt;code&gt;WithDeadline&lt;/code&gt; function again.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;package context&#xA;&#xA;// WithDeadline returns a derived context&#xA;// with a deadline no later than d.&#xA;func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;There are two obvious tests to write for &lt;code&gt;WithDeadline&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;The context is &lt;em&gt;not&lt;/em&gt; canceled &lt;em&gt;before&lt;/em&gt; the deadline.&lt;/li&gt;&#xA;&lt;li&gt;The context &lt;em&gt;is&lt;/em&gt; canceled &lt;em&gt;after&lt;/em&gt; the deadline.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s write a test.&lt;/p&gt;&#xA;&lt;p&gt;To keep the amount of code marginally less overwhelming,&#xA;we&amp;rsquo;ll just test the second case:&#xA;After the deadline expires, the context is canceled.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestWithDeadlineAfterDeadline(t *testing.T) {&#xA;    deadline := time.Now().Add(1 * time.Second)&#xA;    ctx, _ := context.WithDeadline(t.Context(), deadline)&#xA;&#xA;    time.Sleep(time.Until(deadline))&#xA;&#xA;    if err := ctx.Err(); err != context.DeadlineExceeded {&#xA;        t.Fatalf(&amp;quot;context not canceled after deadline&amp;quot;)&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This test is simple:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Use &lt;code&gt;context.WithDeadline&lt;/code&gt; to create a context with a deadline one second in the future.&lt;/li&gt;&#xA;&lt;li&gt;Wait until the deadline.&lt;/li&gt;&#xA;&lt;li&gt;Verify that the context is canceled.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Unfortunately, this test obviously has a problem.&#xA;It sleeps until the exact moment the deadline expires.&#xA;Odds are good that the context has not been canceled yet by the time we examine it.&#xA;At best, this test will be very flaky.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s fix it.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;time.Sleep(time.Until(deadline) + 100*time.Millisecond)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We can sleep until 100ms after the deadline.&#xA;A hundred milliseconds is an eternity in computer terms.&#xA;This should be fine.&lt;/p&gt;&#xA;&lt;p&gt;Unfortunately, we still have two problems.&lt;/p&gt;&#xA;&lt;p&gt;First, this test takes 1.1 seconds to execute.&#xA;That&amp;rsquo;s slow.&#xA;This is a simple test.&#xA;It should execute in milliseconds at the most.&lt;/p&gt;&#xA;&lt;p&gt;Second, this test is flaky.&#xA;A hundred milliseconds is an eternity in computer terms,&#xA;but on an overloaded continuous integration (CI) system&#xA;it isn&amp;rsquo;t unusual to see pauses much longer than that.&#xA;This test will probably pass consistently on a developer&amp;rsquo;s workstation,&#xA;but I would expect occasional failures in a CI system.&lt;/p&gt;&#xA;&lt;h2 id=&#34;slow-or-flaky-pick-two&#34;&gt;Slow or flaky: Pick two&lt;/h2&gt;&#xA;&lt;p&gt;Tests that use real time are always slow or flaky.&#xA;Usually they&amp;rsquo;re both.&#xA;If the test waits longer than necessary, it is slow.&#xA;If it doesn&amp;rsquo;t wait long enough, it is flaky.&#xA;You can make the test more slow and less flaky,&#xA;or less slow and more flaky,&#xA;but you can&amp;rsquo;t make it fast and reliable.&lt;/p&gt;&#xA;&lt;p&gt;We have a lot of tests in the &lt;code&gt;net/http&lt;/code&gt; package which use this approach.&#xA;They&amp;rsquo;re all slow and/or flaky, which is what started me down the road&#xA;which brings us here today.&lt;/p&gt;&#xA;&lt;h2 id=&#34;write-synchronous-functions&#34;&gt;Write synchronous functions?&lt;/h2&gt;&#xA;&lt;p&gt;The simplest way to test an asyncronous function is not to do it.&#xA;Synchronous functions are easy to test.&#xA;If you can transform an asyncronous function into a synchronous one,&#xA;it will be easier to test.&lt;/p&gt;&#xA;&lt;p&gt;For example, if we consider our cache cleanup functions from earlier,&#xA;the synchronous &lt;code&gt;Cleanup&lt;/code&gt; is obviously better than&#xA;the asynchronous &lt;code&gt;CleanupInBackground&lt;/code&gt;.&#xA;The synchronous function is easier to test,&#xA;and the caller can easily start a new goroutine to run it in the background if needed.&#xA;As a general rule,&#xA;the higher up the call stack you can push your concurrency,&#xA;the better.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// CleanupInBackground is hard to test.&#xA;cache.CleanupInBackground()&#xA;&#xA;// Cleanup is easy to test,&#xA;// and easy to run in the background when needed.&#xA;go cache.Cleanup()&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Unfortunately, this sort of transformation isn&amp;rsquo;t always possible.&#xA;For example, &lt;code&gt;context.WithDeadline&lt;/code&gt; is an inherently asynchronous API.&lt;/p&gt;&#xA;&lt;h2 id=&#34;instrument-code-for-testability&#34;&gt;Instrument code for testability?&lt;/h2&gt;&#xA;&lt;p&gt;A better approach is to make our code more testable.&lt;/p&gt;&#xA;&lt;p&gt;Here&amp;rsquo;s an example of what this might look like for our &lt;code&gt;WithDeadline&lt;/code&gt; test:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestWithDeadlineAfterDeadline(t *testing.T) {&#xA;    clock := fakeClock()&#xA;    timeout := 1 * time.Second&#xA;    deadline := clock.Now().Add(timeout)&#xA;&#xA;    ctx, _ := context.WithDeadlineClock(&#xA;        t.Context(), deadline, clock)&#xA;&#xA;    clock.Advance(timeout)&#xA;    context.WaitUntilIdle(ctx)&#xA;    if err := ctx.Err(); err != context.DeadlineExceeded {&#xA;        t.Fatalf(&amp;quot;context not canceled after deadline&amp;quot;)&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Instead of using real time, we use a fake time implementation.&#xA;Using fake time avoids unnecessarily slow tests,&#xA;because we never wait around doing nothing.&#xA;It also helps avoid test flakiness,&#xA;since the current time only changes when the test adjusts it.&lt;/p&gt;&#xA;&lt;p&gt;There are various fake time packages out there,&#xA;or you can write your own.&lt;/p&gt;&#xA;&lt;p&gt;To use fake time, we need to modify our API to accept a fake clock.&#xA;I&amp;rsquo;ve added a &lt;code&gt;context.WithDeadlineClock&lt;/code&gt; function here,&#xA;that takes an additional clock parameter:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;ctx, _ := context.WithDeadlineClock(&#xA;    t.Context(), deadline, clock)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;When we advance our fake clock, we have a problem.&#xA;Advancing time is an asynchrounous operation.&#xA;Sleeping goroutines may wake up,&#xA;timers may send on their channels,&#xA;and timer functions may run.&#xA;We need to wait for that work to finish before we can test&#xA;the expected behavior of the system.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve added a &lt;code&gt;context.WaitUntilIdle&lt;/code&gt; function here,&#xA;which waits for any background work related to a context to complete:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;clock.Advance(timeout)&#xA;context.WaitUntilIdle(ctx)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This is a simple example, but it demonstrates&#xA;the two fundamental principles of writing testable concurrent code:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Use fake time (if you use time).&lt;/li&gt;&#xA;&lt;li&gt;Have some way to wait for quiescence,&#xA;which is a fancy way of saying&#xA;&amp;ldquo;all background activity has stopped and the system is stable&amp;rdquo;.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;The interesting question, of course, is how we do this.&#xA;I&amp;rsquo;ve glossed over the details in this example because&#xA;there are some big downsides to this approach.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s hard.&#xA;Using a fake clock isn&amp;rsquo;t difficult,&#xA;but identifying when background concurrent work is finished&#xA;and it is safe to examine the state of the system is.&lt;/p&gt;&#xA;&lt;p&gt;Your code becomes less idiomatic.&#xA;You can&amp;rsquo;t use standard time package functions.&#xA;You need to be very careful to keep track of everything happening&#xA;in the background.&lt;/p&gt;&#xA;&lt;p&gt;You need to instrument not just your code,&#xA;but any other packages you use.&#xA;If you call any third-party concurrent code,&#xA;you&amp;rsquo;re probably out of luck.&lt;/p&gt;&#xA;&lt;p&gt;Worst of all, it can be just about impossible&#xA;to retrofit this approach into an existing codebase.&lt;/p&gt;&#xA;&lt;p&gt;I attempted to apply this approach to Go&amp;rsquo;s HTTP implementation,&#xA;and while I had some success at doing so in places,&#xA;the HTTP/2 server simply defeated me.&#xA;In particular, adding instrumentation to detect quiescence&#xA;without extensive rewriting proved infeasible,&#xA;or at least beyond my skills.&lt;/p&gt;&#xA;&lt;h2 id=&#34;horrible-runtime-hacks&#34;&gt;Horrible runtime hacks?&lt;/h2&gt;&#xA;&lt;p&gt;What do we do if we can&amp;rsquo;t make our code testable?&lt;/p&gt;&#xA;&lt;p&gt;What if instead of instrumenting our code,&#xA;we had a way to observe the behavior of the uninstrumented system?&lt;/p&gt;&#xA;&lt;p&gt;A Go program consists of a set of goroutines.&#xA;Those goroutines have states.&#xA;We just need to wait until all the goroutines have stopped running.&lt;/p&gt;&#xA;&lt;p&gt;Unfortunately, the Go runtime doesn&amp;rsquo;t provide any way to tell what&#xA;those goroutines are doing. Or does it?&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;runtime&lt;/code&gt; package contains a function that gives us a stack trace&#xA;for every running goroutine, as well as their states.&#xA;This is text intended for human consumption,&#xA;but we could parse that output.&#xA;Could we use this to detect quiescence?&lt;/p&gt;&#xA;&lt;p&gt;Now, of course this is a terrible idea.&#xA;There is no guarantee that the format of these stack traces will be stable over time.&#xA;You should not do this.&lt;/p&gt;&#xA;&lt;p&gt;I did it.&#xA;And it worked.&#xA;In fact, it worked surprisingly well.&lt;/p&gt;&#xA;&lt;p&gt;With a simple implementation of a fake clock,&#xA;a small amount of instrumentation to keep track of what goroutines were part of the test,&#xA;and some horrifying abuse of &lt;code&gt;runtime.Stack&lt;/code&gt;,&#xA;I finally had a way to write fast, reliable tests for the &lt;code&gt;http&lt;/code&gt; package.&lt;/p&gt;&#xA;&lt;p&gt;The underlying implementation of these tests was horrible,&#xA;but it demonstrated that there was a useful concept here.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-better-way&#34;&gt;A better way&lt;/h2&gt;&#xA;&lt;p&gt;Go may have built-in concurrency,&#xA;but testing programs that use that concurrency is hard.&lt;/p&gt;&#xA;&lt;p&gt;We&amp;rsquo;re faced with an unfortunate choice:&#xA;We can write simple, idiomatic code, but it will be impossible to test quickly and reliably;&#xA;or we can write testable code, but it will be complicated and unidiomatic.&lt;/p&gt;&#xA;&lt;p&gt;So we asked ourselves what we can do to make this better.&lt;/p&gt;&#xA;&lt;p&gt;As we saw earlier, the two fundamental features required to write testable concurrent code are&#xA;fake time and a way to wait for quiescence.&lt;/p&gt;&#xA;&lt;p&gt;We need a better way to to wait for quiescence.&#xA;We should be able to ask the runtime when background goroutines have finished their work.&#xA;We also want to be able to limit the scope of this query to a single test,&#xA;so that unrelated tests do not interfere with each other.&lt;/p&gt;&#xA;&lt;p&gt;We also need better support for testing programs using fake time.&lt;/p&gt;&#xA;&lt;p&gt;It isn&amp;rsquo;t hard to make a fake time implementation,&#xA;but code which uses an implementation like this is not idiomatic.&lt;/p&gt;&#xA;&lt;p&gt;Idiomatic code will use a &lt;code&gt;time.Timer&lt;/code&gt;,&#xA;but it is not possible to create a fake &lt;code&gt;Timer&lt;/code&gt;.&#xA;We asked ourselves whether we should provide a way for tests to&#xA;create a fake &lt;code&gt;Timer&lt;/code&gt;, where the test controls when the timer fires.&lt;/p&gt;&#xA;&lt;p&gt;A testing implementation of time needs to define an entirely new version of the &lt;code&gt;time&lt;/code&gt; package,&#xA;and pass that to every function that operates on time.&#xA;We considered whether we should define a common time interface,&#xA;in the same way that &lt;code&gt;net.Conn&lt;/code&gt; is a common interface describing a network connection.&lt;/p&gt;&#xA;&lt;p&gt;What we realized, however, is that unlike network connections,&#xA;there is only one possible implementation of fake time.&#xA;A fake network may want to introduce latency or errors.&#xA;Time, in contrast, does only one thing: It moves forward.&#xA;Tests need to control the rate at which time progresses,&#xA;but a timer scheduled to fire ten seconds in the future&#xA;should always fire ten (possibly fake) seconds in the future.&lt;/p&gt;&#xA;&lt;p&gt;In addition, we don&amp;rsquo;t want to upset the entire Go ecosystem.&#xA;Most programs today use functions in the time package.&#xA;We want to keep those programs not only working,&#xA;but idiomatic.&lt;/p&gt;&#xA;&lt;p&gt;This led to the conclusion that what we need is a way for a test to&#xA;tell the time package to use a fake clock,&#xA;in much the same way that the Go playground uses a fake clock.&#xA;Unlike the playground,&#xA;we need to limit the scope of that change to a single test.&#xA;(It may not be obvious that the Go playground uses a fake clock,&#xA;because we turn any fake delays into real delays on the front end,&#xA;but it does.)&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-synctest-experiment&#34;&gt;The &lt;code&gt;synctest&lt;/code&gt; experiment&lt;/h2&gt;&#xA;&lt;p&gt;And so in Go 1.24 we introduced &lt;a href=&#34;/pkg/testing/synctest&#34;&gt;&lt;code&gt;testing/synctest&lt;/code&gt;&lt;/a&gt;,&#xA;a new, experimental package to simplify testing concurrent programs.&#xA;Over the months following the release of Go 1.24&#xA;we gathered feedback from early adopters.&#xA;(Thank you to everyone who tried it out!)&#xA;We made a number of changes to address problems and shortcomings.&#xA;And now, in Go 1.25, we&amp;rsquo;ve released the &lt;code&gt;testing/synctest&lt;/code&gt; package&#xA;as part of the standard library.&lt;/p&gt;&#xA;&lt;p&gt;It lets you run a function in what we&amp;rsquo;re calling a &amp;ldquo;bubble&amp;rdquo;.&#xA;Within the bubble, the time package uses a fake clock,&#xA;and the &lt;code&gt;synctest&lt;/code&gt; package provides a function to wait for the bubble to quiesce.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-synctest-package&#34;&gt;The &lt;code&gt;synctest&lt;/code&gt; package&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;code&gt;synctest&lt;/code&gt; package contains just two functions.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;package synctest&#xA;&#xA;// Test executes f in a new bubble.&#xA;// Goroutines in the bubble use a fake clock.&#xA;func Test(t *testing.T, f func(*testing.T))&#xA;&#xA;// Wait waits for background activity in the bubble to complete.&#xA;func Wait()&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;a href=&#34;/pkg/testing/synctest#Test&#34;&gt;&lt;code&gt;Test&lt;/code&gt;&lt;/a&gt; executes a function in a new bubble.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;/pkg/testing/synctest#Wait&#34;&gt;&lt;code&gt;Wait&lt;/code&gt;&lt;/a&gt; blocks until every goroutine in the bubble is blocked&#xA;waiting for some other goroutine in the bubble.&#xA;We call that state being &amp;ldquo;durably blocked&amp;rdquo;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;testing-with-synctest&#34;&gt;Testing with synctest&lt;/h2&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s look at an example of synctest in action.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestWithDeadlineAfterDeadline(t *testing.T) {&#xA;    synctest.Test(t, func(t *testing.T) {&#xA;        deadline := time.Now().Add(1 * time.Second)&#xA;        ctx, _ := context.WithDeadline(t.Context(), deadline)&#xA;&#xA;        time.Sleep(time.Until(deadline))&#xA;        synctest.Wait()&#xA;        if err := ctx.Err(); err != context.DeadlineExceeded {&#xA;            t.Fatalf(&amp;quot;context not canceled after deadline&amp;quot;)&#xA;        }&#xA;    })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This might look a little familiar.&#xA;This is the naïve test for &lt;code&gt;context.WithDeadline&lt;/code&gt; that we looked at earlier.&#xA;The only changes are that we&amp;rsquo;ve wrapped the test in&#xA;a &lt;code&gt;synctest.Test&lt;/code&gt; call to execute it in a bubble&#xA;and we have added a &lt;code&gt;synctest.Wait&lt;/code&gt; call.&lt;/p&gt;&#xA;&lt;p&gt;This test is fast and reliable.&#xA;It runs almost instantaneously.&#xA;It precisely tests the expected behavior of the system under test.&#xA;It also requires no modification of the &lt;code&gt;context&lt;/code&gt; package.&lt;/p&gt;&#xA;&lt;p&gt;Using the &lt;code&gt;synctest&lt;/code&gt; package,&#xA;we can write simple, idiomatic code&#xA;and test it reliably.&lt;/p&gt;&#xA;&lt;p&gt;This is a very simple example, of course,&#xA;but this is a real test of real production code.&#xA;If &lt;code&gt;synctest&lt;/code&gt; had existed when the &lt;code&gt;context&lt;/code&gt; package was written,&#xA;we would have had a much easier time writing tests for it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;time&#34;&gt;Time&lt;/h2&gt;&#xA;&lt;p&gt;Time in the bubble behaves much the same as the fake time in the Go playground.&#xA;Time starts at midnight, January 1, 2000 UTC.&#xA;If you need to run a test at some specific point in time for some reason,&#xA;you can just sleep until then.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestAtSpecificTime(t *testing.T) {&#xA;   synctest.Test(t, func(t *testing.T) {&#xA;       // 2000-01-01 00:00:00 +0000 UTC&#xA;       t.Log(time.Now().In(time.UTC))&#xA;&#xA;       // This does not take 25 years.&#xA;       time.Sleep(time.Until(&#xA;           time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)))&#xA;&#xA;       // 2025-01-01 00:00:00 +0000 UTC&#xA;       t.Log(time.Now().In(time.UTC))&#xA;   })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Time only passes when every goroutine in the bubble has blocked.&#xA;You can think of the bubble as simulating an infinitely fast computer:&#xA;Any amount of computation takes no time.&lt;/p&gt;&#xA;&lt;p&gt;The following test will always print that zero seconds&#xA;of fake time have elapsed since the start of the test,&#xA;no matter how much real time has passed.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestExpensiveWork(t *testing.T) {&#xA;   synctest.Test(t, func(t *testing.T) {&#xA;       start := time.Now()&#xA;       for range 1e7 {&#xA;           // do expensive work&#xA;       }&#xA;       t.Log(time.Since(start)) // 0s&#xA;   })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In the next test, the &lt;code&gt;time.Sleep&lt;/code&gt; call will return immediately,&#xA;rather than waiting for ten real seconds.&#xA;The test will always print that exactly ten fake seconds&#xA;have passed since the start of the test.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestSleep(t *testing.T) {&#xA;   synctest.Test(t, func(t *testing.T) {&#xA;       start := time.Now()&#xA;       time.Sleep(10 * time.Second)&#xA;       t.Log(time.Since(start)) // 10s&#xA;   })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;waiting-for-quiescence&#34;&gt;Waiting for quiescence&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;/pkg/testing/synctest#Wait&#34;&gt;&lt;code&gt;synctest.Wait&lt;/code&gt;&lt;/a&gt; function&#xA;lets us wait for background activity to complete.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestWait(t *testing.T) {&#xA;   synctest.Test(t, func(t *testing.T) {&#xA;       done := false&#xA;       go func() {&#xA;           done = true&#xA;       }()&#xA;&#xA;       // Wait for the above goroutine to finish.&#xA;       synctest.Wait()&#xA;&#xA;       t.Log(done) // true&#xA;   })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If we didn&amp;rsquo;t have the &lt;code&gt;Wait&lt;/code&gt; call in the above test,&#xA;we would have a race condition:&#xA;One goroutine modifies the &lt;code&gt;done&lt;/code&gt; variable&#xA;while another reads from it without synchronization.&#xA;The &lt;code&gt;Wait&lt;/code&gt; call provides that synchronization.&lt;/p&gt;&#xA;&lt;p&gt;You may be familiar with the &lt;code&gt;-race&lt;/code&gt; test flag,&#xA;which enables the data race detector.&#xA;The race detector is aware of the synchronization provided by &lt;code&gt;Wait&lt;/code&gt;,&#xA;and does not complain about this test.&#xA;If we forgot the &lt;code&gt;Wait&lt;/code&gt; call, the race detector would correctly complain.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;synctest.Wait&lt;/code&gt; function provides synchronization,&#xA;but the passage of time does not.&lt;/p&gt;&#xA;&lt;p&gt;In the next example, one goroutine writes to the &lt;code&gt;done&lt;/code&gt; variable&#xA;while another sleeps for one nanosecond before reading from it.&#xA;It should be obvious that when run with a real clock outside a synctest bubble,&#xA;this code contains a race condition.&#xA;Inside a synctest bubble,&#xA;while the fake clock ensures that the goroutine completes before &lt;code&gt;time.Sleep&lt;/code&gt; returns,&#xA;the race detector will still report the data race,&#xA;just like it would if this code were run outside a synctest bubble.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestTimeDataRace(t *testing.T) {&#xA;   synctest.Test(t, func(t *testing.T) {&#xA;       done := false&#xA;       go func() {&#xA;           done = true // write&#xA;       }()&#xA;&#xA;       time.Sleep(1 * time.Nanosecond)&#xA;&#xA;       t.Log(done)     // read (unsynchronized)&#xA;   })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Adding a &lt;code&gt;Wait&lt;/code&gt; call provides explicit synchronization and fixes the data race:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;time.Sleep(1 * time.Nanosecond)&#xA;synctest.Wait() // synchronize&#xA;t.Log(done)     // read&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;example-iocopy&#34;&gt;Example: &lt;code&gt;io.Copy&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;Taking advantage of the synchronization provided by &lt;code&gt;synctest.Wait&lt;/code&gt; allows us&#xA;to write simpler tests with less explicit synchronization.&lt;/p&gt;&#xA;&lt;p&gt;For example, consider this test of &lt;a href=&#34;/pkg/io#Copy&#34;&gt;&lt;code&gt;io.Copy&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestIOCopy(t *testing.T) {&#xA;   synctest.Test(t, func(t *testing.T) {&#xA;       srcReader, srcWriter := io.Pipe()&#xA;       defer srcWriter.Close()&#xA;&#xA;       var dst bytes.Buffer&#xA;       go io.Copy(&amp;amp;dst, srcReader)&#xA;&#xA;       data := &amp;quot;1234&amp;quot;&#xA;       srcWriter.Write([]byte(&amp;quot;1234&amp;quot;))&#xA;       synctest.Wait()&#xA;&#xA;       if got, want := dst.String(), data; got != want {&#xA;           t.Errorf(&amp;quot;Copy wrote %q, want %q&amp;quot;, got, want)&#xA;       }&#xA;   })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;code&gt;io.Copy&lt;/code&gt; function copies data from an &lt;code&gt;io.Reader&lt;/code&gt; to an &lt;code&gt;io.Writer&lt;/code&gt;.&#xA;You might not immediately think of &lt;code&gt;io.Copy&lt;/code&gt; as a concurrent function,&#xA;since it blocks until the copy has completed.&#xA;However, providing data to &lt;code&gt;io.Copy&lt;/code&gt;&amp;rsquo;s reader is an asynchronous operation:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Copy&lt;/code&gt; calls the reader&amp;rsquo;s &lt;code&gt;Read&lt;/code&gt; method;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Read&lt;/code&gt; returns some data;&lt;/li&gt;&#xA;&lt;li&gt;and the data is written to the writer at a later time.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In this test, we are verifying that &lt;code&gt;io.Copy&lt;/code&gt; writes new data to the writer&#xA;without waiting to fill its buffer.&lt;/p&gt;&#xA;&lt;p&gt;Looking at the test step by step,&#xA;we first create an &lt;code&gt;io.Pipe&lt;/code&gt; to serve as the source &lt;code&gt;io.Copy&lt;/code&gt; reads from:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;srcReader, srcWriter := io.Pipe()&#xA;defer srcWriter.Close()&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We call &lt;code&gt;io.Copy&lt;/code&gt; in a new goroutine,&#xA;copying from the read end of the pipe into a &lt;code&gt;bytes.Buffer&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;var dst bytes.Buffer&#xA;go io.Copy(&amp;amp;dst, srcReader)&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We write to the other end of the pipe,&#xA;and wait for &lt;code&gt;io.Copy&lt;/code&gt; to handle the data:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;data := &amp;quot;1234&amp;quot;&#xA;srcWriter.Write([]byte(&amp;quot;1234&amp;quot;))&#xA;synctest.Wait()&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Finally, we verify that the destination buffer contains the desired data:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;if got, want := dst.String(), data; got != want {&#xA;    t.Errorf(&amp;quot;Copy wrote %q, want %q&amp;quot;, got, want)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We don&amp;rsquo;t need to add a mutex or other synchronization around the destination buffer,&#xA;because &lt;code&gt;synctest.Wait&lt;/code&gt; ensures that it is never accessed concurrently.&lt;/p&gt;&#xA;&lt;p&gt;This test demonstrates a few important points.&lt;/p&gt;&#xA;&lt;p&gt;Even synchronous functions like &lt;code&gt;io.Copy&lt;/code&gt;,&#xA;which do not perform additional background work after they return,&#xA;may exhibit asynchronous behaviors.&lt;/p&gt;&#xA;&lt;p&gt;Using &lt;code&gt;synctest.Wait&lt;/code&gt;, we can test those behaviors.&lt;/p&gt;&#xA;&lt;p&gt;Note also that this test does not work with time.&#xA;Many asynchronous systems involve time, but not all.&lt;/p&gt;&#xA;&lt;h2 id=&#34;bubble-exit&#34;&gt;Bubble exit&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;code&gt;synctest.Test&lt;/code&gt; function waits for all goroutines in the bubble to exit&#xA;before returning.&#xA;Time stops advancing after the root goroutine (the goroutine started by &lt;code&gt;Test&lt;/code&gt;) returns.&lt;/p&gt;&#xA;&lt;p&gt;In the next example, &lt;code&gt;Test&lt;/code&gt; waits for the background goroutine to run and exit&#xA;before it returns:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestWaitForGoroutine(t *testing.T) {&#xA;    synctest.Test(t, func(t *testing.T) {&#xA;        go func() {&#xA;            // This runs before synctest.Test returns.&#xA;        }()&#xA;    })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In this example, we schedule a &lt;code&gt;time.AfterFunc&lt;/code&gt; for a time in the future.&#xA;The bubble&amp;rsquo;s root goroutine returns before that time is reached,&#xA;so the &lt;code&gt;AfterFunc&lt;/code&gt; never runs:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestDoNotWaitForTimer(t *testing.T) {&#xA;    synctest.Test(t, func(t *testing.T) {&#xA;        time.AfterFunc(1 * time.Nanosecond, func() {&#xA;            // This never runs.&#xA;        })&#xA;    })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In the next example, we start a goroutine that sleeps.&#xA;The root goroutine returns and time stops advancing.&#xA;The bubble is now deadlocked,&#xA;because &lt;code&gt;Test&lt;/code&gt; is waiting for all goroutines in the bubble to finish&#xA;but the sleeping goroutine is waiting for time to advance.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func TestDeadlock(t *testing.T) {&#xA;    synctest.Test(t, func(t *testing.T) {&#xA;        go func() {&#xA;            // This sleep never returns and the test deadlocks.&#xA;            time.Sleep(1 * time.Nanosecond)&#xA;        }()&#xA;    })&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;deadlocks&#34;&gt;Deadlocks&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;code&gt;synctest&lt;/code&gt; package panics when a bubble is deadlocked&#xA;due to every goroutine in the bubble being durably blocked on&#xA;another goroutine in the bubble.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;--- FAIL: Test (0.00s)&#xA;--- FAIL: TestDeadlock (0.00s)&#xA;panic: deadlock: main bubble goroutine has exited but blocked goroutines remain [recovered, repanicked]&#xA;&#xA;goroutine 7 [running]:&#xA;(stacks elided for clarity)&#xA;&#xA;goroutine 10 [sleep (durable), synctest bubble 1]:&#xA;time.Sleep(0x1)&#xA;    /Users/dneil/src/go/src/runtime/time.go:361 +0x130&#xA;_.TestDeadlock.func1.1()&#xA;    /tmp/s/main_test.go:13 +0x20&#xA;created by _.TestDeadlock.func1 in goroutine 9&#xA;    /tmp/s/main_test.go:11 +0x24&#xA;FAIL    _   0.173s&#xA;FAIL&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The runtime will print stack traces for every goroutine in the deadlocked bubble.&lt;/p&gt;&#xA;&lt;p&gt;When printing the status of a bubbled goroutine,&#xA;the runtime indicates when the goroutine is durably blocked.&#xA;You can see that the sleeping goroutine in this test is durably blocked.&lt;/p&gt;&#xA;&lt;h2 id=&#34;durable-blocking&#34;&gt;Durable blocking&lt;/h2&gt;&#xA;&lt;p&gt;&amp;ldquo;Durably blocking&amp;rdquo; is a core concept in synctest.&lt;/p&gt;&#xA;&lt;p&gt;A goroutine is durably blocked when it is not only blocked,&#xA;but when it can only be unblocked by another goroutine in the same bubble.&lt;/p&gt;&#xA;&lt;p&gt;When every goroutine in a bubble is durably blocked:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;code&gt;synctest.Wait&lt;/code&gt; returns.&lt;/li&gt;&#xA;&lt;li&gt;If there is no &lt;code&gt;synctest.Wait&lt;/code&gt; call in progress,&#xA;fake time advances instantly to the next point that will wake a goroutine.&lt;/li&gt;&#xA;&lt;li&gt;If there is no goroutine that can be woken by advancing time,&#xA;the bubble is deadlocked and the test fails.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;It is important for us to make a distinction between a goroutine which is merely blocked&#xA;and one which is &lt;em&gt;durably&lt;/em&gt; blocked.&#xA;We don&amp;rsquo;t want to declare a deadlock when a goroutine is temporarily blocked on&#xA;some event arising outside its bubble.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s look at some ways in which a goroutine can block non-durably.&lt;/p&gt;&#xA;&lt;h3 id=&#34;not-durably-blocking-io-files-pipes-network-connections-etc&#34;&gt;Not durably blocking: I/O (files, pipes, network connections, etc.)&lt;/h3&gt;&#xA;&lt;p&gt;The most important limitation is that I/O is not durably blocking,&#xA;including network I/O.&#xA;A goroutine reading from a network connection may be blocked,&#xA;but it will be unblocked by data arriving on that connection.&lt;/p&gt;&#xA;&lt;p&gt;This is obviously true for a connection to some network service,&#xA;but it is also true for a loopback connection,&#xA;even when the reader and writer are both in the same bubble.&lt;/p&gt;&#xA;&lt;p&gt;When we write data to a network socket,&#xA;even a loopback socket,&#xA;the data is passed to the kernel for delivery.&#xA;There is a period of time between the write system call returning&#xA;and the kernel notifying the other side of the connection that data is available.&#xA;The Go runtime cannot distinguish between a goroutine blocked waiting for&#xA;data that is already in the kernel&amp;rsquo;s buffers&#xA;and one blocked waiting for data that will not arrive.&lt;/p&gt;&#xA;&lt;p&gt;This means that tests of networked programs using synctest&#xA;usually cannot use real network connections.&#xA;Instead, they should use an in-memory fake.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m not going to go over the process of creating a fake network here,&#xA;but the &lt;code&gt;synctest&lt;/code&gt; package documentation contains&#xA;&lt;a href=&#34;/pkg/testing/synctest#hdr-Example__HTTP_100_Continue&#34;&gt;a complete worked example&lt;/a&gt;&#xA;of testing an HTTP client and server communicating over a fake network.&lt;/p&gt;&#xA;&lt;h3 id=&#34;not-durably-blocking-syscalls-cgo-calls-anything-that-isnt-go&#34;&gt;Not durably blocking: syscalls, cgo calls, anything that isn&amp;rsquo;t Go&lt;/h3&gt;&#xA;&lt;p&gt;Syscalls and cgo calls are not durably blocking.&#xA;We can only reason about the state of goroutines executing Go code.&lt;/p&gt;&#xA;&lt;h3 id=&#34;not-durably-blocking-mutexes&#34;&gt;Not durably blocking: Mutexes&lt;/h3&gt;&#xA;&lt;p&gt;Perhaps surprisingly, mutexes are not durably blocking.&#xA;This is a decision born of practicality:&#xA;Mutexes are often used to guard global state,&#xA;so a bubbled goroutine will often need to acquire a mutex held outside its bubble.&#xA;Mutexes are highly performance-sensitive,&#xA;so adding additional instrumentation to them&#xA;risks slowing down non-test programs.&lt;/p&gt;&#xA;&lt;p&gt;We can test programs that use mutexes with synctest,&#xA;but the fake clock will not advance while a goroutine is blocked on mutex acquisition.&#xA;This hasn&amp;rsquo;t posed a problem in any case we&amp;rsquo;ve encountered,&#xA;but it is something to be aware of.&lt;/p&gt;&#xA;&lt;h3 id=&#34;durably-blocking-timesleep&#34;&gt;Durably blocking: &lt;code&gt;time.Sleep&lt;/code&gt;&lt;/h3&gt;&#xA;&lt;p&gt;So what is durably blocking?&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;time.Sleep&lt;/code&gt; is obviously durable,&#xA;since time can only advance when every goroutine in the bubble is durably blocked.&lt;/p&gt;&#xA;&lt;h3 id=&#34;durably-blocking-send-or-receive-on-channels-created-in-the-same-bubble&#34;&gt;Durably blocking: send or receive on channels created in the same bubble&lt;/h3&gt;&#xA;&lt;p&gt;Channel operations on channels created within the same bubble are durable.&lt;/p&gt;&#xA;&lt;p&gt;We make a distinction between bubbled channels (created in a bubble)&#xA;and unbubbled channels (created outside any bubble).&#xA;This means that a function using a global channel for synchronization,&#xA;for example to control access to a globally cached resource,&#xA;can be safely called from within a bubble.&lt;/p&gt;&#xA;&lt;p&gt;Trying to operate on a bubbled channel from outside its bubble is an error.&lt;/p&gt;&#xA;&lt;h3 id=&#34;durably-blocking-syncwaitgroup-belonging-to-the-same-bubble&#34;&gt;Durably blocking: &lt;code&gt;sync.WaitGroup&lt;/code&gt; belonging to the same bubble&lt;/h3&gt;&#xA;&lt;p&gt;We also associate &lt;code&gt;sync.WaitGroup&lt;/code&gt;s with bubbles.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;WaitGroup&lt;/code&gt; doesn&amp;rsquo;t have a constructor,&#xA;so we make the association with the bubble implicitly on the first call to &lt;code&gt;Go&lt;/code&gt; or &lt;code&gt;Add&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;As with channels,&#xA;waiting on a &lt;code&gt;WaitGroup&lt;/code&gt; belonging to the same bubble is durably blocking,&#xA;and waiting on one from outside the bubble is not.&#xA;Calling &lt;code&gt;Go&lt;/code&gt; or &lt;code&gt;Add&lt;/code&gt; on a &lt;code&gt;WaitGroup&lt;/code&gt; belonging to a different bubble is an error.&lt;/p&gt;&#xA;&lt;h3 id=&#34;durably-blocking-synccondwait&#34;&gt;Durably blocking: &lt;code&gt;sync.Cond.Wait&lt;/code&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Waiting on a &lt;code&gt;sync.Cond&lt;/code&gt; is always durably blocking.&#xA;Waking up a goroutine waiting on a &lt;code&gt;Cond&lt;/code&gt; in a different bubble is an error.&lt;/p&gt;&#xA;&lt;h3 id=&#34;durably-blocking-select&#34;&gt;Durably blocking: &lt;code&gt;select{}&lt;/code&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Finally, an empty select is durably blocking.&#xA;(A select with cases is durably blocking if all the operations in it are so.)&lt;/p&gt;&#xA;&lt;p&gt;That&amp;rsquo;s the complete list of durably blocking operations.&#xA;It isn&amp;rsquo;t very long,&#xA;but it&amp;rsquo;s enough to handle almost all real-world programs.&lt;/p&gt;&#xA;&lt;p&gt;The rule is that a goroutine is durably blocked when it is blocked,&#xA;and we can guarantee that it can only be unblocked&#xA;by another goroutine in its bubble.&lt;/p&gt;&#xA;&lt;p&gt;In cases where it is possible to attempt to wake a bubbled goroutine from outside its bubble,&#xA;we panic.&#xA;For example, it is an error to operate on a bubbled channel from outside its bubble.&lt;/p&gt;&#xA;&lt;h2 id=&#34;changes-from-124-to-125&#34;&gt;Changes from 1.24 to 1.25&lt;/h2&gt;&#xA;&lt;p&gt;We released an experimental version of the &lt;code&gt;synctest&lt;/code&gt; package in Go 1.24.&#xA;To ensure that early adopters were aware of the experimental status of the package,&#xA;you needed to set a GOEXPERIMENT flag to make the package visible.&lt;/p&gt;&#xA;&lt;p&gt;The feedback we received from those early adopters was invaluable,&#xA;both in demonstrating that the package is useful&#xA;and in uncovering areas where the API needed work.&lt;/p&gt;&#xA;&lt;p&gt;These are some of the changes made between the experimental version&#xA;and the version released in Go 1.25.&lt;/p&gt;&#xA;&lt;h3 id=&#34;replaced-run-with-test&#34;&gt;Replaced Run with Test&lt;/h3&gt;&#xA;&lt;p&gt;The original version of the API created a bubble with a &lt;code&gt;Run&lt;/code&gt; function:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// Run executes f in a new bubble.&#xA;func Run(f func())&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It became clear that we needed a way to create a &lt;code&gt;*testing.T&lt;/code&gt;&#xA;that is scoped to a bubble.&#xA;For example, &lt;code&gt;t.Cleanup&lt;/code&gt; should run cleanup functions in the same bubble&#xA;they are registered in, not after the bubble exits.&#xA;We renamed &lt;code&gt;Run&lt;/code&gt; to &lt;code&gt;Test&lt;/code&gt; and made it create a &lt;code&gt;T&lt;/code&gt; scoped to the lifetime&#xA;of the new bubble.&lt;/p&gt;&#xA;&lt;h3 id=&#34;time-stops-when-a-bubbles-root-goroutine-returns&#34;&gt;Time stops when a bubble&amp;rsquo;s root goroutine returns&lt;/h3&gt;&#xA;&lt;p&gt;We originally continued to advance time within a bubble for so long as&#xA;the bubble contained any goroutines waiting for future events.&#xA;This turned out to be very confusing when a long-lived goroutine never returned,&#xA;such as a goroutine reading forever from a &lt;code&gt;time.Ticker&lt;/code&gt;.&#xA;We now stop advancing time when a bubble&amp;rsquo;s root goroutine returns.&#xA;If the bubble is blocked waiting for time to advance,&#xA;this results in a deadlock and a panic which can be analyzed.&lt;/p&gt;&#xA;&lt;h3 id=&#34;removed-cases-where-durable-wasnt&#34;&gt;Removed cases where &amp;ldquo;durable&amp;rdquo; wasn&amp;rsquo;t&lt;/h3&gt;&#xA;&lt;p&gt;We cleaned up the definition of &amp;ldquo;durably blocking&amp;rdquo;.&#xA;The original implementation had cases where a durably blocked goroutine could&#xA;be unblocked from outside the bubble.&#xA;For example, channels recorded whether they were created in a bubble,&#xA;but not which in which bubble they were created,&#xA;so one bubble could unblock a channel in a different bubble.&#xA;The current implementation contains no cases we know of&#xA;where a durably blocked goroutine can be unblocked from outside its bubble.&lt;/p&gt;&#xA;&lt;h3 id=&#34;better-stack-traces&#34;&gt;Better stack traces&lt;/h3&gt;&#xA;&lt;p&gt;We made improvements to the information printed in stack traces.&#xA;When a bubble deadlocks, we by default now only print stacks for the goroutines in that bubble.&#xA;Stack traces also clearly indicate which goroutines in a bubble are durably blocked.&lt;/p&gt;&#xA;&lt;h3 id=&#34;randomized-events-happening-at-the-same-time&#34;&gt;Randomized events happening at the same time&lt;/h3&gt;&#xA;&lt;p&gt;We made improvements to the randomization of events happening at the same time.&#xA;Originally, timers scheduled to fire at the same instant&#xA;would always do so in the order they were created.&#xA;This ordering is now randomized.&lt;/p&gt;&#xA;&lt;h2 id=&#34;future-work&#34;&gt;Future work&lt;/h2&gt;&#xA;&lt;p&gt;We&amp;rsquo;re pretty happy with the synctest package at the moment.&lt;/p&gt;&#xA;&lt;p&gt;Aside from the inevitable bug fixes,&#xA;we don&amp;rsquo;t currently expect any major changes to it in the future.&#xA;Of course, with wider adoption it is always possible that we&amp;rsquo;ll discover something&#xA;that needs doing.&lt;/p&gt;&#xA;&lt;p&gt;One possible area of work is to improve the detection of durably blocked goroutines.&#xA;It would be nice if we could make mutex operations durably blocking,&#xA;with a restriction that a mutex acquired in a bubble must be released&#xA;from within the same bubble.&lt;/p&gt;&#xA;&lt;p&gt;Testing networked code with synctest requires a fake network.&#xA;The &lt;code&gt;net.Pipe&lt;/code&gt; function can create a fake &lt;code&gt;net.Conn&lt;/code&gt;,&#xA;but there is currently no standard library function that creates&#xA;a fake &lt;code&gt;net.Listener&lt;/code&gt; or &lt;code&gt;net.PacketConn&lt;/code&gt;.&#xA;In addition, the &lt;code&gt;net.Conn&lt;/code&gt; returned by &lt;code&gt;net.Pipe&lt;/code&gt; is synchronous&amp;ndash;every write blocks&#xA;until a read consumes the data&amp;ndash;which is not representative of real network behavior.&#xA;Perhaps we should add a good fake implementations of common network interfaces&#xA;to the standard library.&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;That&amp;rsquo;s the &lt;code&gt;synctest&lt;/code&gt; package.&lt;/p&gt;&#xA;&lt;p&gt;I can&amp;rsquo;t say that it makes testing concurrent code simple,&#xA;because concurrency is never simple.&#xA;What it does is let you write the simplest possible concurrent code,&#xA;using idiomatic Go,&#xA;and the standard time package,&#xA;and then write fast, reliable tests for it.&lt;/p&gt;&#xA;&lt;p&gt;I hope you find it useful.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/jsonv2-exp&#34;&gt;A new experimental Go API for JSON&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/container-aware-gomaxprocs&#34;&gt;Container-aware GOMAXPROCS&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>Container-aware GOMAXPROCS</title><id>tag:blog.golang.org,2013:blog.golang.org/container-aware-gomaxprocs</id><link rel="alternate" href="https://go.dev/blog/container-aware-gomaxprocs"></link><published>2025-08-20T00:00:00+00:00</published><updated>2025-08-20T00:00:00+00:00</updated><author><name>Michael Pratt and Carlos Amedee</name></author><summary type="html">New GOMAXPROCS defaults in Go 1.25 improve behavior in containers.</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/container-aware-gomaxprocs&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;Container-aware GOMAXPROCS&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Michael Pratt and Carlos Amedee&lt;br&gt;&#xA;      20 August 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;Go 1.25 includes new container-aware &lt;code&gt;GOMAXPROCS&lt;/code&gt; defaults, providing more sensible default behavior for many container workloads, avoiding throttling that can impact tail latency, and improving Go&amp;rsquo;s out-of-the-box production-readiness.&#xA;In this post, we will dive into how Go schedules goroutines, how that scheduling interacts with container-level CPU controls, and how Go can perform better with awareness of container CPU controls.&lt;/p&gt;&#xA;&lt;h2 id=&#34;gomaxprocs&#34;&gt;&lt;code&gt;GOMAXPROCS&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;One of Go&amp;rsquo;s strengths is its built-in and easy-to-use concurrency via goroutines.&#xA;From a semantic perspective, goroutines appear very similar to operating system threads, enabling us to write simple, blocking code.&#xA;On the other hand, goroutines are more lightweight than operating system threads, making it much cheaper to create and destroy them on the fly.&lt;/p&gt;&#xA;&lt;p&gt;While a Go implementation could map each goroutine to a dedicated operating system thread, Go keeps goroutines lightweight with a runtime scheduler that makes threads fungible.&#xA;Any Go-managed thread can run any goroutine, so creating a new goroutine doesn&amp;rsquo;t require creating a new thread, and waking a goroutine doesn&amp;rsquo;t necessarily require waking another thread.&lt;/p&gt;&#xA;&lt;p&gt;That said, along with a scheduler comes scheduling questions.&#xA;For example, exactly how many threads should we use to run goroutines?&#xA;If 1,000 goroutines are runnable, should we schedule them on 1,000 different threads?&lt;/p&gt;&#xA;&lt;p&gt;This is where &lt;a href=&#34;/pkg/runtime#GOMAXPROCS&#34;&gt;&lt;code&gt;GOMAXPROCS&lt;/code&gt;&lt;/a&gt; comes in.&#xA;Semantically, &lt;code&gt;GOMAXPROCS&lt;/code&gt; tells the Go runtime the &amp;ldquo;available parallelism&amp;rdquo; that Go should use.&#xA;In more concrete terms, &lt;code&gt;GOMAXPROCS&lt;/code&gt; is the maximum number of threads to use for running goroutines at once.&lt;/p&gt;&#xA;&lt;p&gt;So, if &lt;code&gt;GOMAXPROCS=8&lt;/code&gt; and there are 1,000 runnable goroutines, Go will use 8 threads to run 8 goroutines at a time.&#xA;Often, goroutines run for a very short time and then block, at which point Go will switch to running another goroutine on that same thread.&#xA;Go will also preempt goroutines that don&amp;rsquo;t block on their own, ensuring all goroutines get a chance to run.&lt;/p&gt;&#xA;&lt;p&gt;From Go 1.5 through Go 1.24, &lt;code&gt;GOMAXPROCS&lt;/code&gt; defaulted to the total number of CPU cores on the machine.&#xA;Note that in this post, &amp;ldquo;core&amp;rdquo; more precisely means &amp;ldquo;logical CPU.&amp;rdquo;&#xA;For example, a machine with 4 physical CPUs with hyperthreading has 8 logical CPUs.&lt;/p&gt;&#xA;&lt;p&gt;This typically makes a good default for &amp;ldquo;available parallelism&amp;rdquo; because it naturally matches the available parallelism of the hardware.&#xA;That is, if there are 8 cores and Go runs more than 8 threads at a time, the operating system will have to multiplex these threads onto the 8 cores, much like how Go multiplexes goroutines onto threads.&#xA;This extra layer of scheduling is not always a problem, but it is unnecessary overhead.&lt;/p&gt;&#xA;&lt;h2 id=&#34;container-orchestration&#34;&gt;Container Orchestration&lt;/h2&gt;&#xA;&lt;p&gt;Another of Go&amp;rsquo;s core strengths is the convenience of deploying applications via a container, and managing the number of cores Go uses is especially important when deploying an application within a container orchestration platform.&#xA;Container orchestration platforms like &lt;a href=&#34;https://kubernetes.io/&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Kubernetes&lt;/a&gt; take a set of machine resources and schedule containers within the available resources based on requested resources.&#xA;Packing as many containers as possible within a cluster&amp;rsquo;s resources requires the platform to be able to predict the resource usage of each scheduled container.&#xA;We want Go to adhere to the resource utilization constraints that the container orchestration platform sets.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s explore the effects of the &lt;code&gt;GOMAXPROCS&lt;/code&gt; setting in the context of Kubernetes, as an example.&#xA;Platforms like Kubernetes provide a mechanism to limit the resources consumed by a container.&#xA;Kubernetes has the concept of CPU resource limits, which signal to the underlying operating system how many core resources a specific container or set of containers will be allocated.&#xA;Setting a CPU limit translates to the creation of a Linux &lt;a href=&#34;https://docs.kernel.org/admin-guide/cgroup-v2.html#cpu&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;control group&lt;/a&gt; CPU bandwidth limit.&lt;/p&gt;&#xA;&lt;p&gt;Before Go 1.25, Go was unaware of CPU limits set by orchestration platforms.&#xA;Instead, it would set &lt;code&gt;GOMAXPROCS&lt;/code&gt; to the number of cores on the machine it was deployed to.&#xA;If there was a CPU limit in place, the application may try to use far more CPU than allowed by the limit.&#xA;To prevent an application from exceeding its limit, the Linux kernel will &lt;a href=&#34;https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#how-pods-with-resource-limits-are-run&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;throttle&lt;/a&gt; the application.&lt;/p&gt;&#xA;&lt;p&gt;Throttling is a blunt mechanism for restricting containers that would otherwise exceed their CPU limit: it completely pauses application execution for the remainder of the throttling period.&#xA;The throttling period is typically 100ms, so throttling can cause substantial tail latency impact compared to the softer scheduling multiplexing effects of a lower &lt;code&gt;GOMAXPROCS&lt;/code&gt; setting.&#xA;Even if the application never has much parallelism, tasks performed by the Go runtime—such as garbage collection—can still cause CPU spikes that trigger throttling.&lt;/p&gt;&#xA;&lt;h2 id=&#34;new-default&#34;&gt;New default&lt;/h2&gt;&#xA;&lt;p&gt;We want Go to provide efficient and reliable defaults when possible, so in Go 1.25, we have made &lt;code&gt;GOMAXPROCS&lt;/code&gt; take into account its container environment by default.&#xA;If a Go process is running inside a container with a CPU limit, &lt;code&gt;GOMAXPROCS&lt;/code&gt; will default to the CPU limit if it is less than the core count.&lt;/p&gt;&#xA;&lt;p&gt;Container orchestration systems may adjust container CPU limits on the fly, so Go 1.25 will also periodically check the CPU limit and adjust &lt;code&gt;GOMAXPROCS&lt;/code&gt; automatically if it changes.&lt;/p&gt;&#xA;&lt;p&gt;Both of these defaults only apply if &lt;code&gt;GOMAXPROCS&lt;/code&gt; is otherwise unspecified.&#xA;Setting the &lt;code&gt;GOMAXPROCS&lt;/code&gt; environment variable or calling &lt;code&gt;runtime.GOMAXPROCS&lt;/code&gt; continues to behave as before.&#xA;The &lt;a href=&#34;/pkg/runtime#GOMAXPROCS&#34;&gt;&lt;code&gt;runtime.GOMAXPROCS&lt;/code&gt;&lt;/a&gt; documentation covers the details of the new behavior.&lt;/p&gt;&#xA;&lt;h2 id=&#34;slightly-different-models&#34;&gt;Slightly different models&lt;/h2&gt;&#xA;&lt;p&gt;Both &lt;code&gt;GOMAXPROCS&lt;/code&gt; and a container CPU limit place a limit on the maximum amount of CPU the process can use, but their models are subtly different.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;GOMAXPROCS&lt;/code&gt; is a parallelism limit.&#xA;If &lt;code&gt;GOMAXPROCS=8&lt;/code&gt; Go will never run more than 8 goroutines at a time.&lt;/p&gt;&#xA;&lt;p&gt;By contrast, CPU limits are a throughput limit.&#xA;That is, they limit the total CPU time used in some period of wall time.&#xA;The default period is 100ms.&#xA;So an &amp;ldquo;8 CPU limit&amp;rdquo; is actually a limit of 800ms of CPU time every 100ms of wall time.&lt;/p&gt;&#xA;&lt;p&gt;This limit could be filled by running 8 threads continuously for the entire 100ms, which is equivalent to &lt;code&gt;GOMAXPROCS=8&lt;/code&gt;.&#xA;On the other hand, the limit could also be filled by running 16 threads for 50ms each, with each thread being idle or blocked for the other 50ms.&lt;/p&gt;&#xA;&lt;p&gt;In other words, a CPU limit doesn&amp;rsquo;t limit the total number of CPUs the container can run on.&#xA;It only limits total CPU time.&lt;/p&gt;&#xA;&lt;p&gt;Most applications have fairly consistent CPU usage across 100ms periods, so the new &lt;code&gt;GOMAXPROCS&lt;/code&gt; default is a pretty good match to the CPU limit, and certainly better than the total core count!&#xA;However, it is worth noting that particularly spiky workloads may see a latency increase from this change due to &lt;code&gt;GOMAXPROCS&lt;/code&gt; preventing short-lived spikes of additional threads beyond the CPU limit average.&lt;/p&gt;&#xA;&lt;p&gt;In addition, since CPU limits are a throughput limit, they can have a fractional component (e.g., 2.5 CPU).&#xA;On the other hand, &lt;code&gt;GOMAXPROCS&lt;/code&gt; must be a positive integer.&#xA;Thus, Go must round the limit to a valid &lt;code&gt;GOMAXPROCS&lt;/code&gt; value.&#xA;Go always rounds up to enable use of the full CPU limit.&lt;/p&gt;&#xA;&lt;h2 id=&#34;cpu-requests&#34;&gt;CPU Requests&lt;/h2&gt;&#xA;&lt;p&gt;Go&amp;rsquo;s new &lt;code&gt;GOMAXPROCS&lt;/code&gt; default is based on the container&amp;rsquo;s CPU limit, but container orchestration systems also provide a &amp;ldquo;CPU request&amp;rdquo; control.&#xA;While the CPU limit specifies the maximum CPU a container may use, the CPU request specifies the minimum CPU guaranteed to be available to the container at all times.&lt;/p&gt;&#xA;&lt;p&gt;It is common to create containers with a CPU request but no CPU limit, as this allows containers to utilize machine CPU resources beyond the CPU request that would otherwise be idle due to lack of load from other containers.&#xA;Unfortunately, this means that Go cannot set &lt;code&gt;GOMAXPROCS&lt;/code&gt; based on the CPU request, which would prevent utilization of additional idle resources.&lt;/p&gt;&#xA;&lt;p&gt;Containers with a CPU request are still &lt;a href=&#34;https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#how-pods-with-resource-limits-are-run&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;constrained&lt;/a&gt; when exceeding their request if the machine is busy.&#xA;The weight-based constraint of exceeding requests is &amp;ldquo;softer&amp;rdquo; than the hard period-based throttling of CPU limits, but CPU spikes from high &lt;code&gt;GOMAXPROCS&lt;/code&gt; can still have an adverse impact on application behavior.&lt;/p&gt;&#xA;&lt;h2 id=&#34;should-i-set-a-cpu-limit&#34;&gt;Should I set a CPU limit?&lt;/h2&gt;&#xA;&lt;p&gt;We have learned about the problems caused by having &lt;code&gt;GOMAXPROCS&lt;/code&gt; too high, and that setting a container CPU limit allows Go to automatically set an appropriate &lt;code&gt;GOMAXPROCS&lt;/code&gt;, so an obvious next step is to wonder whether all containers should set a CPU limit.&lt;/p&gt;&#xA;&lt;p&gt;While that may be good advice to automatically get a reasonable &lt;code&gt;GOMAXPROCS&lt;/code&gt; defaults, there are many other factors to consider when deciding whether to set a CPU limit, such as prioritizing utilization of idle resources by avoiding limits vs prioritizing predictable latency by setting limits.&lt;/p&gt;&#xA;&lt;p&gt;The worst behaviors from a mismatch between &lt;code&gt;GOMAXPROCS&lt;/code&gt; and effective CPU limits occur when &lt;code&gt;GOMAXPROCS&lt;/code&gt; is significantly higher than the effective CPU limit.&#xA;For example, a small container receiving 2 CPUs running on a 128 core machine.&#xA;These are the cases where it is most valuable to consider setting an explicit CPU limit, or, alternatively, explicitly setting &lt;code&gt;GOMAXPROCS&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;Go 1.25 provides more sensible default behavior for many container workloads by setting &lt;code&gt;GOMAXPROCS&lt;/code&gt; based on container CPU limits.&#xA;Doing so avoids throttling that can impact tail latency, improves efficiency, and generally tries to ensure Go is production-ready out-of-the-box.&#xA;You can get the new defaults simply by setting the Go version to 1.25.0 or higher in your &lt;code&gt;go.mod&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Thanks to everyone in the community that contributed to the &lt;a href=&#34;/issue/33803&#34;&gt;long&lt;/a&gt; &lt;a href=&#34;/issue/73193&#34;&gt;discussions&lt;/a&gt; that made this a reality, and in particular to feedback from the maintainers of &lt;a href=&#34;https://pkg.go.dev/go.uber.org/automaxprocs&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;go.uber.org/automaxprocs&lt;/code&gt;&lt;/a&gt; from Uber, which has long provided similar behavior to its users.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/testing-time&#34;&gt;Testing Time (and other asynchronicities)&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/go1.25&#34;&gt;Go 1.25 is released&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>Go 1.25 is released</title><id>tag:blog.golang.org,2013:blog.golang.org/go1.25</id><link rel="alternate" href="https://go.dev/blog/go1.25"></link><published>2025-08-12T00:00:00+00:00</published><updated>2025-08-12T00:00:00+00:00</updated><author><name>Dmitri Shuralyov, on behalf of the Go team</name></author><summary type="html">Go 1.25 adds container-aware GOMAXPROCS, testing/synctest package, experimental GC, experimental encoding/json/v2, and more.</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/go1.25&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;Go 1.25 is released&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Dmitri Shuralyov, on behalf of the Go team&lt;br&gt;&#xA;      12 August 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;Today the Go team is pleased to release Go 1.25.&#xA;You can find its binary archives and installers on the &lt;a href=&#34;/dl/&#34;&gt;download page&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Go 1.25 comes with improvements over Go 1.24 across&#xA;its &lt;a href=&#34;/doc/go1.25#tools&#34;&gt;tools&lt;/a&gt;,&#xA;the &lt;a href=&#34;/doc/go1.25#runtime&#34;&gt;runtime&lt;/a&gt;,&#xA;&lt;a href=&#34;/doc/go1.25#compiler&#34;&gt;compiler&lt;/a&gt;,&#xA;&lt;a href=&#34;/doc/go1.25#linker&#34;&gt;linker&lt;/a&gt;,&#xA;and the &lt;a href=&#34;/doc/go1.25#library&#34;&gt;standard library&lt;/a&gt;,&#xA;including the addition of one &lt;a href=&#34;/doc/go1.25#new-testingsynctest-package&#34;&gt;new package&lt;/a&gt;.&#xA;There are &lt;a href=&#34;/doc/go1.25#ports&#34;&gt;port-specific&lt;/a&gt; changes&#xA;and &lt;a href=&#34;/doc/godebug#go-125&#34;&gt;&lt;code&gt;GODEBUG&lt;/code&gt; settings&lt;/a&gt; updates.&lt;/p&gt;&#xA;&lt;p&gt;Some of the additions in Go 1.25 are in an experimental stage&#xA;and become exposed only when you explicitly opt in.&#xA;Notably, a &lt;a href=&#34;/doc/go1.25#new-experimental-garbage-collector&#34;&gt;new experimental garbage collector&lt;/a&gt;,&#xA;and a &lt;a href=&#34;/doc/go1.25#json_v2&#34;&gt;new experimental &lt;code&gt;encoding/json/v2&lt;/code&gt; package&lt;/a&gt;&#xA;are available for you to try ahead of time and provide your feedback.&#xA;It really helps if you&amp;rsquo;re able to do that!&lt;/p&gt;&#xA;&lt;p&gt;Please refer to the &lt;a href=&#34;/doc/go1.25&#34;&gt;Go 1.25 Release Notes&lt;/a&gt; for the complete list&#xA;of additions, changes and improvements in Go 1.25.&lt;/p&gt;&#xA;&lt;p&gt;Over the next few weeks, follow-up blog posts will cover some of the topics&#xA;relevant to Go 1.25 in more detail. Check back in later to read those posts.&lt;/p&gt;&#xA;&lt;p&gt;Thanks to everyone who contributed to this release by writing code, filing bugs,&#xA;trying out experimental additions, sharing feedback, and testing the release candidates.&#xA;Your efforts helped make Go 1.25 as stable as possible.&#xA;As always, if you notice any problems, please &lt;a href=&#34;/issue/new&#34;&gt;file an issue&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;We hope you enjoy using the new release!&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/container-aware-gomaxprocs&#34;&gt;Container-aware GOMAXPROCS&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/fips140&#34;&gt;The FIPS 140-3 Go Cryptographic Module&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>The FIPS 140-3 Go Cryptographic Module</title><id>tag:blog.golang.org,2013:blog.golang.org/fips140</id><link rel="alternate" href="https://go.dev/blog/fips140"></link><published>2025-07-15T00:00:00+00:00</published><updated>2025-07-15T00:00:00+00:00</updated><author><name>Filippo Valsorda (Geomys), Daniel McCarney (Geomys), and Roland Shoemaker (Google)</name></author><summary type="html">Go now has a built-in, native FIPS 140-3 compliant mode.</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/fips140&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;The FIPS 140-3 Go Cryptographic Module&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Filippo Valsorda (Geomys), Daniel McCarney (Geomys),  and Roland Shoemaker (Google)&lt;br&gt;&#xA;      15 July 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;FIPS 140 is a standard for cryptography implementations and, although it doesn’t&#xA;necessarily improve security, FIPS 140 compliance is a requirement in certain&#xA;regulated environments that are increasingly adopting Go. Until now, FIPS 140&#xA;compliance has been a significant source of friction for Go users, requiring&#xA;unsupported solutions with safety, developer experience, functionality, release&#xA;velocity, and compliance issues.&lt;/p&gt;&#xA;&lt;p&gt;Go is addressing this growing need with native FIPS 140 support built right into&#xA;the standard library and the &lt;code&gt;go&lt;/code&gt; command, making Go the easiest, most secure&#xA;way to comply with FIPS 140. The FIPS 140-3 validated Go Cryptographic Module&#xA;now underlies Go’s built-in crypto libraries, starting with the Go Cryptographic&#xA;Module v1.0.0 that is included in Go 1.24, released last February.&lt;/p&gt;&#xA;&lt;p&gt;The v1.0.0 module has been awarded &lt;a href=&#34;https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/details?validation=39260&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Cryptographic Algorithm Validation Program&#xA;(CAVP) certificate A6650&lt;/a&gt;, was submitted to the Cryptographic Module&#xA;Validation Program (CMVP), and reached the &lt;a href=&#34;https://csrc.nist.gov/Projects/cryptographic-module-validation-program/modules-in-process/modules-in-process-list&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Modules In Process List&lt;/a&gt; in May.&#xA;Modules on the MIP list are awaiting NIST review and can already be deployed in&#xA;certain regulated environments.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://geomys.org&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Geomys&lt;/a&gt; led the implementation effort in collaboration with the Go Security&#xA;Team, and is pursuing a broadly applicable FIPS 140-3 validation for the benefit&#xA;of the Go community. Google and other industry stakeholders have a contractual&#xA;relationship with Geomys to include specific Operating Environments in the&#xA;certificate.&lt;/p&gt;&#xA;&lt;p&gt;Further details on the module are available in the&#xA;&lt;a href=&#34;/doc/security/fips140&#34;&gt;documentation&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Some Go users currently rely on the &lt;a href=&#34;/doc/security/fips140#goboringcrypto&#34;&gt;Go+BoringCrypto&lt;/a&gt; GOEXPERIMENT, or on one&#xA;of its forks, as part of their FIPS 140 compliance strategy. Unlike the FIPS&#xA;140-3 Go Cryptographic Module, Go+BoringCrypto was never officially supported&#xA;and had significant developer experience issues, since it was produced&#xA;exclusively for the internal needs of Google. It will be removed in a future&#xA;release once Google migrates to the native module.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-native-developer-experience&#34;&gt;A native developer experience&lt;/h2&gt;&#xA;&lt;p&gt;The module integrates completely transparently into Go applications. In fact,&#xA;every Go program built with Go 1.24 already uses it for all FIPS 140-3 approved&#xA;algorithms! The module is just another name for the&#xA;&lt;code&gt;crypto/internal/fips140/...&lt;/code&gt; packages of the standard library, which provide&#xA;the implementation of operations exposed by packages such as &lt;code&gt;crypto/ecdsa&lt;/code&gt; and&#xA;&lt;code&gt;crypto/rand&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;These packages involve no cgo, meaning they cross-compile like any other Go&#xA;program, they pay no FFI performance overhead, and they don’t suffer from&#xA;&lt;a href=&#34;/blog/tob-crypto-audit#cgo-memory-management&#34;&gt;memory management security issues&lt;/a&gt;, unlike Go+BoringCrypto and its forks.&lt;/p&gt;&#xA;&lt;p&gt;When starting a Go binary, the module can be put into FIPS 140-3 mode with the&#xA;&lt;code&gt;fips140=on&lt;/code&gt; &lt;a href=&#34;/doc/godebug&#34;&gt;GODEBUG option&lt;/a&gt;, which can be set as an environment variable or&#xA;through the &lt;code&gt;go.mod&lt;/code&gt; file. If FIPS 140-3 mode is enabled, the module will use&#xA;the NIST DRBG for randomness, &lt;code&gt;crypto/tls&lt;/code&gt; will automatically only negotiate&#xA;FIPS 140-3 approved TLS versions and algorithms, and it will perform the&#xA;mandatory self-tests on initialization and during key generation. That’s it;&#xA;there are no other behavior differences.&lt;/p&gt;&#xA;&lt;p&gt;There is also an experimental stricter mode, &lt;code&gt;fips140=only&lt;/code&gt;, which causes all&#xA;non-approved algorithms to return errors or panic. We understand this might be&#xA;too inflexible for most deployments and are &lt;a href=&#34;/issue/74630&#34;&gt;looking for&#xA;feedback&lt;/a&gt; on what a policy enforcement framework&#xA;might look like.&lt;/p&gt;&#xA;&lt;p&gt;Finally, applications can use the &lt;a href=&#34;/doc/security/fips140#the-gofips140-environment-variable&#34;&gt;&lt;code&gt;GOFIPS140&lt;/code&gt; environment&#xA;variable&lt;/a&gt;&#xA;to build against older, validated versions of the &lt;code&gt;crypto/internal/fips140/...&lt;/code&gt;&#xA;packages. &lt;code&gt;GOFIPS140&lt;/code&gt; works like &lt;code&gt;GOOS&lt;/code&gt; and &lt;code&gt;GOARCH&lt;/code&gt;, and if set to&#xA;&lt;code&gt;GOFIPS140=v1.0.0&lt;/code&gt; the program will be built against the v1.0.0 snapshot of the&#xA;packages as they were submitted for validation to CMVP. This snapshot ships with&#xA;the rest of the Go standard library, as &lt;code&gt;lib/fips140/v1.0.0.zip&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;When using &lt;code&gt;GOFIPS140&lt;/code&gt;, the &lt;code&gt;fips140&lt;/code&gt; GODEBUG defaults to &lt;code&gt;on&lt;/code&gt;, so putting it&#xA;all together, all that’s needed to build against the FIPS 140-3 module and run&#xA;in FIPS 140-3 mode is &lt;code&gt;GOFIPS140=v1.0.0 go build&lt;/code&gt;. That’s it.&lt;/p&gt;&#xA;&lt;p&gt;If a toolchain is built with &lt;code&gt;GOFIPS140&lt;/code&gt; set, all builds it produces will&#xA;default to that value.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;GOFIPS140&lt;/code&gt; version used to build a binary can be verified with&#xA;&lt;code&gt;go version -m&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Future versions of Go will continue shipping and working with v1.0.0 of the Go&#xA;Cryptographic Module until the next version is fully certified by Geomys, but&#xA;some new cryptography features might not be available when building against old&#xA;modules. Starting with Go 1.24.3, you can use &lt;code&gt;GOFIPS140=inprocess&lt;/code&gt; to&#xA;dynamically select the latest module for which a Geomys validation has reached&#xA;the In Process stage. Geomys plans to validate new module versions at least&#xA;every year—to avoid leaving FIPS 140 builds too far behind—and every time a&#xA;vulnerability in the module can’t be mitigated in the calling standard library&#xA;code.&lt;/p&gt;&#xA;&lt;h2 id=&#34;uncompromising-security&#34;&gt;Uncompromising security&lt;/h2&gt;&#xA;&lt;p&gt;Our first priority in developing the module has been matching or exceeding the&#xA;security of the existing Go standard library cryptography packages. It might be&#xA;surprising, but sometimes the easiest way to achieve and demonstrate compliance&#xA;with the FIPS 140 security requirements is not to exceed them. We declined to&#xA;accept that.&lt;/p&gt;&#xA;&lt;p&gt;For example, &lt;code&gt;crypto/ecdsa&lt;/code&gt; &lt;a href=&#34;https://cs.opensource.google/go/go/+/refs/tags/go1.23.0:src/crypto/ecdsa/ecdsa.go;l=417&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;always produced hedged signatures&lt;/a&gt;. Hedged&#xA;signatures generate nonces by combining the private key, the message, and random&#xA;bytes. Like &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc6979&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;deterministic ECDSA&lt;/a&gt;, they protect against failure of the&#xA;random number generator, which would otherwise leak the private key(!). Unlike&#xA;deterministic ECDSA, they are also resistant to &lt;a href=&#34;https://github.com/MystenLabs/ed25519-unsafe-libs&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;API issues&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/Differential_fault_analysis&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;fault&#xA;attacks&lt;/a&gt;, and they don’t leak message equality. FIPS 186-5 introduced support&#xA;for &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc6979&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;RFC 6979&lt;/a&gt; deterministic ECDSA, but not for hedged ECDSA.&lt;/p&gt;&#xA;&lt;p&gt;Instead of downgrading to regular randomized or deterministic ECDSA signatures&#xA;in FIPS 140-3 mode (or worse, across modes), we &lt;a href=&#34;https://github.com/golang/go/commit/9776d028f4b99b9a935dae9f63f32871b77c49af&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;switched the hedging&#xA;algorithm&lt;/a&gt; and connected dots across half a dozen documents to &lt;a href=&#34;https://github.com/cfrg/draft-irtf-cfrg-det-sigs-with-noise/issues/6#issuecomment-2067819904&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;prove the new&#xA;one is a compliant composition of a DRBG and traditional ECDSA&lt;/a&gt;. While at it,&#xA;we also &lt;a href=&#34;/doc/go1.24#cryptoecdsapkgcryptoecdsa&#34;&gt;added opt-in support for deterministic signatures&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Another example is random number generation. FIPS 140-3 has strict rules on how&#xA;cryptographic randomness is generated, which essentially enforce the use of a&#xA;userspace &lt;a href=&#34;https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;CSPRNG&lt;/a&gt;. Conversely, we believe the kernel is best suited to&#xA;produce secure random bytes, because it’s best positioned to collect entropy&#xA;from the system, and to detect when processes or even virtual machines are&#xA;cloned (which could lead to reuse of supposedly random bytes). Hence,&#xA;&lt;a href=&#34;https://pkg.go.dev/crypto/rand&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;crypto/rand&lt;/a&gt; routes every read operation to the kernel.&lt;/p&gt;&#xA;&lt;p&gt;To square this circle, in FIPS 140-3 mode we maintain a compliant userspace NIST&#xA;DRBG based on AES-256-CTR, and then inject into it 128 bits sourced from the&#xA;kernel at every read operation. This extra entropy is considered “uncredited”&#xA;additional data for FIPS 140-3 purposes, but in practice makes it as strong as&#xA;reading directly from the kernel—even if slower.&lt;/p&gt;&#xA;&lt;p&gt;Finally, all of the Go Cryptographic Module v1.0.0 was in scope for the &lt;a href=&#34;/blog/tob-crypto-audit&#34;&gt;recent&#xA;security audit by Trail of Bits&lt;/a&gt;, and was&#xA;not affected by the only non-informational finding.&lt;/p&gt;&#xA;&lt;p&gt;Combined with the memory safety guarantees provided by the Go compiler and&#xA;runtime, we believe this delivers on our goal of making Go one of the easiest,&#xA;most secure solutions for FIPS 140 compliance.&lt;/p&gt;&#xA;&lt;h2 id=&#34;broad-platform-support&#34;&gt;Broad platform support&lt;/h2&gt;&#xA;&lt;p&gt;A FIPS 140-3 module is only compliant if operated on a tested or “Vendor&#xA;Affirmed” Operating Environment, essentially a combination of operating system&#xA;and hardware platform. To enable as many Go use cases as possible, the Geomys&#xA;validation is tested on &lt;a href=&#34;https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/details?product=19371&amp;amp;displayMode=Aggregated&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;one of the most comprehensive sets of Operating&#xA;Environments&lt;/a&gt; in the industry.&lt;/p&gt;&#xA;&lt;p&gt;Geomys’s laboratory tested various Linux flavors (Alpine Linux on Podman, Amazon&#xA;Linux, Google Prodimage, Oracle Linux, Red Hat Enterprise Linux, and SUSE Linux&#xA;Enterprise Server), macOS, Windows, and FreeBSD on a mix of x86-64 (AMD and&#xA;Intel), ARMv8/9 (Ampere Altra, Apple M, AWS Graviton, and Qualcomm Snapdragon),&#xA;ARMv7, MIPS, z/ Architecture, and POWER, for a total of 23 tested environments.&lt;/p&gt;&#xA;&lt;p&gt;Some of these were paid for by stakeholders, others were funded by Geomys for&#xA;the benefit of the Go community.&lt;/p&gt;&#xA;&lt;p&gt;Moreover, the Geomys validation lists a broad set of generic platforms as Vendor&#xA;Affirmed Operating Environments:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Linux 3.10+ on x86-64 and ARMv7/8/9,&lt;/li&gt;&#xA;&lt;li&gt;macOS 11–15 on Apple M processors,&lt;/li&gt;&#xA;&lt;li&gt;FreeBSD 12–14 on x86-64,&lt;/li&gt;&#xA;&lt;li&gt;Windows 10 and Windows Server 2016–2022 on x86-64, and&lt;/li&gt;&#xA;&lt;li&gt;Windows 11 and Windows Server 2025 on x86-64 and ARMv8/9.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;comprehensive-algorithm-coverage&#34;&gt;Comprehensive algorithm coverage&lt;/h2&gt;&#xA;&lt;p&gt;It may be surprising, but even using a FIPS 140-3 approved algorithm implemented&#xA;by a FIPS 140-3 module on a supported Operating Environment is not necessarily&#xA;enough for compliance; the algorithm must have been specifically covered by&#xA;testing as part of validation. Hence, to make it as easy as possible to build&#xA;FIPS 140 compliant applications in Go, all FIPS 140-3 approved algorithms in the&#xA;standard library are implemented by the Go Cryptographic Module and were tested&#xA;as part of the validation, from digital signatures to the TLS key schedule.&lt;/p&gt;&#xA;&lt;p&gt;The post-quantum ML-KEM key exchange (FIPS 203), &lt;a href=&#34;/doc/go1.24#crypto-mlkem&#34;&gt;introduced in Go 1.24&lt;/a&gt;, is also validated, meaning &lt;code&gt;crypto/tls&lt;/code&gt; can establish FIPS 140-3&#xA;compliant post-quantum secure connections with X25519MLKEM768.&lt;/p&gt;&#xA;&lt;p&gt;In some cases, we validated the same algorithms under multiple different NIST&#xA;designations, to make it possible to use them in full compliance for different&#xA;purposes. For example, &lt;a href=&#34;https://words.filippo.io/dispatches/fips-hkdf/&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;HKDF is tested and validated under &lt;em&gt;four&lt;/em&gt; names&lt;/a&gt;:&#xA;SP 800-108 Feedback KDF, SP 800-56C two-step KDF, Implementation Guidance D.P&#xA;OneStepNoCounter KDF, and SP 800-133 Section 6.3 KDF.&lt;/p&gt;&#xA;&lt;p&gt;Finally, we validated some internal algorithms such as CMAC Counter KDF, to make&#xA;it possible to expose future functionality such as &lt;a href=&#34;https://c2sp.org/XAES-256-GCM&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;XAES-256-GCM&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Overall, the native FIPS 140-3 module delivers a better compliance profile than&#xA;Go+BoringCrypto, while making more algorithms available to FIPS 140-3 restricted&#xA;applications.&lt;/p&gt;&#xA;&lt;p&gt;We look forward to the new native Go Cryptographic Module making it easier and&#xA;safer for Go developers to run FIPS 140 compliant workloads.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/go1.25&#34;&gt;Go 1.25 is released&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/generic-interfaces&#34;&gt;Generic interfaces&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>Generic interfaces</title><id>tag:blog.golang.org,2013:blog.golang.org/generic-interfaces</id><link rel="alternate" href="https://go.dev/blog/generic-interfaces"></link><published>2025-07-07T00:00:00+00:00</published><updated>2025-07-07T00:00:00+00:00</updated><author><name>Axel Wagner</name></author><summary type="html">Adding type parameters to interface types is surprisingly powerful</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/generic-interfaces&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;Generic interfaces&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Axel Wagner&lt;br&gt;&#xA;      7 July 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;There is an idea that is not obvious until you hear about it for the first time: as interfaces are types themselves, they too can have type parameters.&#xA;This idea proves to be surprisingly powerful when it comes to expressing constraints on generic functions and types.&#xA;In this post, we&amp;rsquo;ll demonstrate it, by discussing the use of interfaces with type parameters in a couple of common scenarios.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-simple-tree-set&#34;&gt;A simple tree set&lt;/h2&gt;&#xA;&lt;p&gt;As a motivating example, assume we need a generic version of a &lt;a href=&#34;https://en.wikipedia.org/wiki/Binary_search_tree&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;binary search tree&lt;/a&gt;.&#xA;The elements stored in such a tree need to be ordered, so our type parameter needs a constraint that determines the ordering to use.&#xA;A simple option is to use the &lt;a href=&#34;/pkg/cmp#Ordered&#34;&gt;cmp.Ordered&lt;/a&gt; constraint, introduced in Go 1.21.&#xA;It restricts a type parameter to ordered types (strings and numbers) and allows methods of the type to use the built-in ordering operators.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// The zero value of a Tree is a ready-to-use empty tree.&#xA;type Tree[E cmp.Ordered] struct {&#xA;    root *node[E]&#xA;}&#xA;&#xA;func (t *Tree[E]) Insert(element E) {&#xA;    t.root = t.root.insert(element)&#xA;}&#xA;&#xA;type node[E cmp.Ordered] struct {&#xA;    value E&#xA;    left  *node[E]&#xA;    right *node[E]&#xA;}&#xA;&#xA;func (n *node[E]) insert(element E) *node[E] {&#xA;    if n == nil {&#xA;        return &amp;amp;node[E]{value: element}&#xA;    }&#xA;    switch {&#xA;    case element &amp;lt; n.value:&#xA;        n.left = n.left.insert(element)&#xA;    case element &amp;gt; n.value:&#xA;        n.right = n.right.insert(element)&#xA;    }&#xA;    return n&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/H7-n33X7P2h&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;However, this approach has the disadvantage that it only works on basic types for which &lt;code&gt;&amp;lt;&lt;/code&gt; is defined;&#xA;you cannot insert struct types, like &lt;a href=&#34;/pkg/time#Time&#34;&gt;time.Time&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;We can remedy that by requiring the user to provide a comparison function:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// A FuncTree must be created with NewTreeFunc.&#xA;type FuncTree[E any] struct {&#xA;    root *funcNode[E]&#xA;    cmp  func(E, E) int&#xA;}&#xA;&#xA;func NewFuncTree[E any](cmp func(E, E) int) *FuncTree[E] {&#xA;    return &amp;amp;FuncTree[E]{cmp: cmp}&#xA;}&#xA;&#xA;func (t *FuncTree[E]) Insert(element E) {&#xA;    t.root = t.root.insert(t.cmp, element)&#xA;}&#xA;&#xA;type funcNode[E any] struct {&#xA;    value E&#xA;    left  *funcNode[E]&#xA;    right *funcNode[E]&#xA;}&#xA;&#xA;func (n *funcNode[E]) insert(cmp func(E, E) int, element E) *funcNode[E] {&#xA;    if n == nil {&#xA;        return &amp;amp;funcNode[E]{value: element}&#xA;    }&#xA;    sign := cmp(element, n.value)&#xA;    switch {&#xA;    case sign &amp;lt; 0:&#xA;        n.left = n.left.insert(cmp, element)&#xA;    case sign &amp;gt; 0:&#xA;        n.right = n.right.insert(cmp, element)&#xA;    }&#xA;    return n&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/tiEjuxCHtFF&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;This works, but it also comes with downsides.&#xA;We can no longer use the zero value of our container type, because it needs to have an explicitly initialized comparison function.&#xA;And the use of a function field makes it harder for the compiler to inline the comparison calls, which can introduce a significant runtime overhead.&lt;/p&gt;&#xA;&lt;p&gt;Using a method on the element type can solve these issues, because methods are directly associated with a type.&#xA;A method does not have to be explicitly passed and the compiler can see the target of the call and may be able to inline it.&#xA;But how can we express the constraint to require that element types provide the necessary method?&lt;/p&gt;&#xA;&lt;h2 id=&#34;using-the-receiver-in-constraints&#34;&gt;Using the receiver in constraints&lt;/h2&gt;&#xA;&lt;p&gt;The first approach we might try is to define a plain old interface with a &lt;code&gt;Compare&lt;/code&gt; method:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type Comparer interface {&#xA;    Compare(Comparer) int&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;However, we quickly realize that this does not work well.&#xA;To implement this interface, the method&amp;rsquo;s parameter must itself be &lt;code&gt;Comparer&lt;/code&gt;.&#xA;Not only does that mean that the implementation of this method must type-assert the parameter to its own type, it also requires that every type must explicitly refer to our package with the &lt;code&gt;Comparer&lt;/code&gt; type by name (otherwise the method signatures would not be identical).&#xA;That is not very orthogonal.&lt;/p&gt;&#xA;&lt;p&gt;A better approach is to make the &lt;code&gt;Comparer&lt;/code&gt; interface itself generic:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type Comparer[T any] interface {&#xA;    Compare(T) int&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This &lt;code&gt;Comparer&lt;/code&gt; now describes a whole family of interfaces, one for each type that &lt;code&gt;Comparer&lt;/code&gt; may be instantiated with.&#xA;A type that implements &lt;code&gt;Comparer[T]&lt;/code&gt; declares &amp;ldquo;I can compare myself to a &lt;code&gt;T&lt;/code&gt;&amp;rdquo;.&#xA;For instance, &lt;code&gt;time.Time&lt;/code&gt; naturally implements &lt;code&gt;Comparer[time.Time]&lt;/code&gt; because &lt;a href=&#34;/pkg/time#Time.Compare&#34;&gt;it has a matching &lt;code&gt;Compare&lt;/code&gt; method&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// Implements Comparer[Time]&#xA;func (t Time) Compare(u Time) int&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This is better, but not enough.&#xA;What we really want is a constraint that says that a type parameter can be compared to &lt;em&gt;itself&lt;/em&gt;: we want the constraint to be self-referential.&#xA;The subtle insight is that the self-referential aspect does not have to be part of the interface definition itself; specifically, the constraint for &lt;code&gt;T&lt;/code&gt; in the &lt;code&gt;Comparer&lt;/code&gt; type is just &lt;code&gt;any&lt;/code&gt;.&#xA;Instead, it is a consequence of how we use &lt;code&gt;Comparer&lt;/code&gt; as a constraint for the type parameter of &lt;code&gt;MethodTree&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// The zero value of a MethodTree is a ready-to-use empty tree.&#xA;type MethodTree[E Comparer[E]] struct {&#xA;    root *methodNode[E]&#xA;}&#xA;&#xA;func (t *MethodTree[E]) Insert(element E) {&#xA;    t.root = t.root.insert(element)&#xA;}&#xA;&#xA;type methodNode[E Comparer[E]] struct {&#xA;    value E&#xA;    left  *methodNode[E]&#xA;    right *methodNode[E]&#xA;}&#xA;&#xA;func (n *methodNode[E]) insert(element E) *methodNode[E] {&#xA;    if n == nil {&#xA;        return &amp;amp;methodNode[E]{value: element}&#xA;    }&#xA;    sign := element.Compare(n.value)&#xA;    switch {&#xA;    case sign &amp;lt; 0:&#xA;        n.left = n.left.insert(element)&#xA;    case sign &amp;gt; 0:&#xA;        n.right = n.right.insert(element)&#xA;    }&#xA;    return n&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/LuhzYej_2SP&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;Because &lt;code&gt;time.Time&lt;/code&gt; implements &lt;code&gt;Comparer[time.Time]&lt;/code&gt; it is now a valid type argument for this container, and we can still use the zero value as an empty container:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;var t MethodTree[time.Time]&#xA;t.Insert(time.Now())&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;For full flexibility, a library can provide all three API versions.&#xA;If we want to minimize repetition, all versions could use a shared implementation.&#xA;We could use the function version for that, as it is the most general:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type node[E any] struct {&#xA;    value E&#xA;    left  *node[E]&#xA;    right *node[E]&#xA;}&#xA;&#xA;func (n *node[E]) insert(cmp func(E, E) int, element E) *node[E] {&#xA;    if n == nil {&#xA;        return &amp;amp;node[E]{value: element}&#xA;    }&#xA;    sign := cmp(element, n.value)&#xA;    switch {&#xA;    case sign &amp;lt; 0:&#xA;        n.left = n.left.insert(cmp, element)&#xA;    case sign &amp;gt; 0:&#xA;        n.right = n.right.insert(cmp, element)&#xA;    }&#xA;    return n&#xA;}&#xA;&#xA;// Insert inserts element into the tree, if E implements cmp.Ordered.&#xA;func (t *Tree[E]) Insert(element E) {&#xA;    t.root = t.root.insert(cmp.Compare[E], element)&#xA;}&#xA;&#xA;// Insert inserts element into the tree, using the provided comparison function.&#xA;func (t *FuncTree[E]) Insert(element E) {&#xA;    t.root = t.root.insert(t.cmp, element)&#xA;}&#xA;&#xA;// Insert inserts element into the tree, if E implements Comparer[E].&#xA;func (t *MethodTree[E]) Insert(element E) {&#xA;    t.root = t.root.insert(E.Compare, element)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/jzmoaH5eaIv&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;An important observation here is that the shared implementation (the function-based variant) is not constrained in any way.&#xA;It must remain maximally flexible to serve as a common core.&#xA;We also do not store the comparison function in a struct field.&#xA;Instead, we pass it as a parameter because function arguments are easier for the compiler to analyze than struct fields.&lt;/p&gt;&#xA;&lt;p&gt;There is still some amount of boilerplate involved, of course.&#xA;All the exported implementations need to replicate the full API with slightly different call patterns.&#xA;But this part is straightforward to write and to read.&lt;/p&gt;&#xA;&lt;h2 id=&#34;combining-methods-and-type-sets&#34;&gt;Combining methods and type sets&lt;/h2&gt;&#xA;&lt;p&gt;We can use our new tree data structure to implement an ordered set, providing element lookup in logarithmic time.&#xA;Let&amp;rsquo;s now imagine we need to make lookup run in constant time; we might try to do this by maintaining an ordinary Go map alongside the tree:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type OrderedSet[E Comparer[E]] struct {&#xA;    tree     MethodTree[E] // for efficient iteration in order&#xA;    elements map[E]bool    // for (near) constant time lookup&#xA;}&#xA;&#xA;func (s *OrderedSet[E]) Has(e E) bool {&#xA;    return s.elements[e]&#xA;}&#xA;&#xA;func (s *OrderedSet[E]) Insert(e E) {&#xA;    if s.elements == nil {&#xA;        s.elements = make(map[E]bool)&#xA;    }&#xA;    if s.elements[e] {&#xA;        return&#xA;    }&#xA;    s.elements[e] = true&#xA;    s.tree.Insert(e)&#xA;}&#xA;&#xA;func (s *OrderedSet[E]) All() iter.Seq[E] {&#xA;    return func(yield func(E) bool) {&#xA;        s.tree.root.all(yield)&#xA;    }&#xA;}&#xA;&#xA;func (n *node[E]) all(yield func(E) bool) bool {&#xA;    return n == nil || (n.left.all(yield) &amp;amp;&amp;amp; yield(n.value) &amp;amp;&amp;amp; n.right.all(yield))&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/TANUnnSnDqf&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;However, compiling this code will produce an error:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;invalid map key type E (missing comparable constraint)&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The error message tells us that we need to further constrain our type parameter to be able to use it as a map key.&#xA;The &lt;code&gt;comparable&lt;/code&gt; constraint is a special predeclared constraint that is satisfied by all types for which the equality operators &lt;code&gt;==&lt;/code&gt; and &lt;code&gt;!=&lt;/code&gt; are defined.&#xA;In Go, that is also the set of types which can be used as keys for the built-in &lt;code&gt;map&lt;/code&gt; type.&lt;/p&gt;&#xA;&lt;p&gt;We have three options to add this constraint to our type parameter, all with different tradeoffs:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We can &lt;a href=&#34;/ref/spec#Embedded_interfaces&#34;&gt;embed&lt;/a&gt; &lt;code&gt;comparable&lt;/code&gt; into our original &lt;code&gt;Comparer&lt;/code&gt; definition (&lt;a href=&#34;/play/p/g8NLjZCq97q&#34;&gt;playground&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type Comparer[E any] interface {&#xA;    comparable&#xA;    Compare(E) int&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This has the downside that it would also make our &lt;code&gt;Tree&lt;/code&gt; types only usable with types that are &lt;code&gt;comparable&lt;/code&gt;.&#xA;In general, we do not want to unnecessarily restrict generic types.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We can add a new constraint definition (&lt;a href=&#34;/play/p/Z2eg4X8xK5Z&#34;&gt;playground&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type Comparer[E any] interface {&#xA;    Compare(E) int&#xA;}&#xA;&#xA;type ComparableComparer[E any] interface {&#xA;    comparable&#xA;    Comparer[E]&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This is tidy, but it introduces a new identifier (&lt;code&gt;ComparableComparer&lt;/code&gt;) into our API, and naming is hard.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We can add the constraint inline into our more constrained type (&lt;a href=&#34;/play/p/ZfggVma_jNc&#34;&gt;playground&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type OrderedSet[E interface {&#xA;    comparable&#xA;    Comparer[E]&#xA;}] struct {&#xA;    tree     Tree[E]&#xA;    elements map[E]struct{}&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This can become a bit hard to read, especially if it needs to happen often.&#xA;It also makes it harder to reuse the constraint in other places.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Which of these to use is a style choice and ultimately up to personal preference.&lt;/p&gt;&#xA;&lt;h2 id=&#34;not-constraining-generic-interfaces&#34;&gt;(Not) constraining generic interfaces&lt;/h2&gt;&#xA;&lt;p&gt;At this point it is worth discussing constraints on generic interfaces.&#xA;You might want to define an interface for a generic container type.&#xA;For example, say you have an algorithm that requires a set data structure.&#xA;There are many different kinds of set implementations with different tradeoffs.&#xA;Defining an interface for the set operations you require can add flexibility to your package, leaving the decision of what tradeoffs are right for the specific application to the user:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type Set[E any] interface {&#xA;    Insert(E)&#xA;    Delete(E)&#xA;    Has(E) bool&#xA;    All() iter.Seq[E]&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A natural question here is what the constraint on this interface should be.&#xA;If possible, type parameters on generic interfaces should use &lt;code&gt;any&lt;/code&gt; as a constraint, allowing arbitrary types.&lt;/p&gt;&#xA;&lt;p&gt;From our discussions above, the reasons should be clear:&#xA;Different concrete implementations might require different constraints.&#xA;All the &lt;code&gt;Tree&lt;/code&gt; types we have examined above, as well as the &lt;code&gt;OrderedSet&lt;/code&gt; type, can implement &lt;code&gt;Set&lt;/code&gt; for their element types, even though these types have different constraints.&lt;/p&gt;&#xA;&lt;p&gt;The point of defining an interface is to leave the implementation up to the user.&#xA;Since one cannot predict what kinds of constraints a user may want to impose on their implementation, try to leave any constraints (stronger than &lt;code&gt;any&lt;/code&gt;) to concrete implementations, not the interfaces.&lt;/p&gt;&#xA;&lt;h2 id=&#34;pointer-receivers&#34;&gt;Pointer receivers&lt;/h2&gt;&#xA;&lt;p&gt;Let us try to use the &lt;code&gt;Set&lt;/code&gt; interface in an example.&#xA;Consider a function that removes duplicate elements in a sequence:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// Unique removes duplicate elements from the input sequence, yielding only&#xA;// the first instance of any element.&#xA;func Unique[E comparable](input iter.Seq[E]) iter.Seq[E] {&#xA;    return func(yield func(E) bool) {&#xA;        seen := make(map[E]bool)&#xA;        for v := range input {&#xA;            if seen[v] {&#xA;                continue&#xA;            }&#xA;            if !yield(v) {&#xA;                return&#xA;            }&#xA;            seen[v] = true&#xA;        }&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/hsYoFjkU9kA&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;This uses a &lt;code&gt;map[E]bool&lt;/code&gt; as a simple set of &lt;code&gt;E&lt;/code&gt; elements.&#xA;Consequently, it works only for types that are &lt;code&gt;comparable&lt;/code&gt; and which therefore define the built-in equality operators.&#xA;If we want to generalize this to arbitrary types, we need to replace that with a generic set:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// Unique removes duplicate elements from the input sequence, yielding only&#xA;// the first instance of any element.&#xA;func Unique[E any](input iter.Seq[E]) iter.Seq[E] {&#xA;    return func(yield func(E) bool) {&#xA;        var seen Set[E]&#xA;        for v := range input {&#xA;            if seen.Has(v) {&#xA;                continue&#xA;            }&#xA;            if !yield(v) {&#xA;                return&#xA;            }&#xA;            seen.Insert(v)&#xA;        }&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/FZYPNf56nnY&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;However, this does not work.&#xA;&lt;code&gt;Set[E]&lt;/code&gt; is an interface type, and the &lt;code&gt;seen&lt;/code&gt; variable will be initialized to &lt;code&gt;nil&lt;/code&gt;.&#xA;We need to use a concrete implementation of the &lt;code&gt;Set[E]&lt;/code&gt; interface.&#xA;But as we have seen in this post, there is no general implementation of a set that works for &lt;code&gt;any&lt;/code&gt; element type.&lt;/p&gt;&#xA;&lt;p&gt;We have to ask the user to provide a concrete implementation we can use, as an extra type parameter:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// Unique removes duplicate elements from the input sequence, yielding only&#xA;// the first instance of any element.&#xA;func Unique[E any, S Set[E]](input iter.Seq[E]) iter.Seq[E] {&#xA;    return func(yield func(E) bool) {&#xA;        var seen S&#xA;        for v := range input {&#xA;            if seen.Has(v) {&#xA;                continue&#xA;            }&#xA;            if !yield(v) {&#xA;                return&#xA;            }&#xA;            seen.Insert(v)&#xA;        }&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/kjkGy5cNz8T&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;However, if we instantiate this with our set implementation, we run into another problem:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// OrderedSet[E] does not satisfy Set[E] (method All has pointer receiver)&#xA;Unique[E, OrderedSet[E]](slices.Values(s))&#xA;// panic: invalid memory address or nil pointer dereference&#xA;Unique[E, *OrderedSet[E]](slices.Values(s))&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The first problem is clear from the error message: Our type constraint says that the type argument for &lt;code&gt;S&lt;/code&gt; needs to implement the &lt;code&gt;Set[E]&lt;/code&gt; interface.&#xA;And as the methods on &lt;code&gt;OrderedSet&lt;/code&gt; use a pointer receiver, the type argument also has to be the pointer type.&lt;/p&gt;&#xA;&lt;p&gt;When trying to do that, we run into the second problem.&#xA;This stems from the fact that we declare a variable in the implementation:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;var seen S&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If &lt;code&gt;S&lt;/code&gt; is &lt;code&gt;*OrderedSet[E]&lt;/code&gt;, the variable is initialized with &lt;code&gt;nil&lt;/code&gt;, as before.&#xA;Calling &lt;code&gt;seen.Insert&lt;/code&gt; panics.&lt;/p&gt;&#xA;&lt;p&gt;If we only have the pointer type, we cannot get a valid variable of the value type.&#xA;And if we only have the value type, we cannot call pointer-methods on it.&#xA;The consequence is that we need both the value &lt;em&gt;and&lt;/em&gt; the pointer type.&#xA;So we have to introduce an additional type parameter &lt;code&gt;PS&lt;/code&gt; with a new constraint &lt;code&gt;PtrToSet&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// PtrToSet is implemented by a pointer type implementing the Set[E] interface.&#xA;type PtrToSet[S, E any] interface {&#xA;    *S&#xA;    Set[E]&#xA;}&#xA;&#xA;// Unique removes duplicate elements from the input sequence, yielding only&#xA;// the first instance of any element.&#xA;func Unique[E, S any, PS PtrToSet[S, E]](input iter.Seq[E]) iter.Seq[E] {&#xA;    return func(yield func(E) bool) {&#xA;        // We convert to PS, as only that is constrained to have the methods.&#xA;        // The conversion is allowed, because the type set of PS only contains *S.&#xA;        seen := PS(new(S))&#xA;        for v := range input {&#xA;            if seen.Has(v) {&#xA;                continue&#xA;            }&#xA;            if !yield(v) {&#xA;                return&#xA;            }&#xA;            seen.Insert(v)&#xA;        }&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/Kp1jJRVjmYa&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;The trick here is the connection of the two type parameters in the function signature via the extra type parameter on the &lt;code&gt;PtrToSet&lt;/code&gt; interface.&#xA;&lt;code&gt;S&lt;/code&gt; itself is unconstrained, but &lt;code&gt;PS&lt;/code&gt; must have type &lt;code&gt;*S&lt;/code&gt; and it must have the methods we need.&#xA;So effectively, we are restricting &lt;code&gt;S&lt;/code&gt; to have some methods, but those methods need to use a pointer receiver.&lt;/p&gt;&#xA;&lt;p&gt;While the definition of a function with this kind of constraint requires an additional type parameter, importantly this does not complicate code using it:&#xA;as long as this extra type parameter is at the end of the type parameter list, it &lt;a href=&#34;/blog/type-inference&#34;&gt;can be inferred&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// The third type argument is inferred to be *OrderedSet[int]&#xA;Unique[int, OrderedSet[int]](slices.Values(s))&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This is a general pattern, and worth remembering: for when you encounter it in someone else&amp;rsquo;s work, or when you want to use it in your own.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func SomeFunction[T any, PT interface{ *T; SomeMethods }]()&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If you have two type parameters, where one is constrained to be a pointer to the other, the constraint ensures that the relevant methods use a pointer receiver.&lt;/p&gt;&#xA;&lt;h2 id=&#34;should-you-constrain-to-pointer-receivers&#34;&gt;Should you constrain to pointer receivers?&lt;/h2&gt;&#xA;&lt;p&gt;At this point, you might feel pretty overwhelmed.&#xA;This is rather complicated and it seems unreasonable to expect every Go programmer to understand what is going on in this function signature.&#xA;We also had to introduce yet more names into our API.&#xA;When people cautioned against adding generics to Go in the first place, this is one of the things they were worried about.&lt;/p&gt;&#xA;&lt;p&gt;So if you find yourself entangled in these problems, it is worth taking a step back.&#xA;We can often avoid this complexity by thinking about our problem in a different way.&#xA;In this example, we built a function that takes an &lt;code&gt;iter.Seq[E]&lt;/code&gt; and returns an &lt;code&gt;iter.Seq[E]&lt;/code&gt; with the unique elements.&#xA;But to do the deduplication, we needed to collect the unique elements into a set.&#xA;And as this requires us to allocate the space for the entire result, we do not really benefit from representing the result as a stream.&lt;/p&gt;&#xA;&lt;p&gt;If we rethink this problem, we can avoid the extra type parameter altogether by using &lt;code&gt;Set[E]&lt;/code&gt; as a regular interface value:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;// InsertAll adds all unique elements from seq into set.&#xA;func InsertAll[E any](set Set[E], seq iter.Seq[E]) {&#xA;    for v := range seq {&#xA;        set.Insert(v)&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/woZcHodAgaa&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;By using &lt;code&gt;Set&lt;/code&gt; as a plain interface type, it is clear that the caller has to provide a valid value of their concrete implementation.&#xA;This is a very common pattern.&#xA;And if they need an &lt;code&gt;iter.Seq[E]&lt;/code&gt;, they can simply call &lt;code&gt;All()&lt;/code&gt; on the &lt;code&gt;set&lt;/code&gt; to obtain one.&lt;/p&gt;&#xA;&lt;p&gt;This complicates things for callers slightly, but it has another advantage over the constraint to pointer receivers:&#xA;remember that we started with a &lt;code&gt;map[E]bool&lt;/code&gt; as a simple set type.&#xA;It is easy to implement the &lt;code&gt;Set[E]&lt;/code&gt; interface on that basis:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;type HashSet[E comparable] map[E]bool&#xA;&#xA;func (s HashSet[E]) Insert(v E)       { s[v] = true }&#xA;func (s HashSet[E]) Delete(v E)       { delete(s, v) }&#xA;func (s HashSet[E]) Has(v E) bool     { return s[v] }&#xA;func (s HashSet[E]) All() iter.Seq[E] { return maps.Keys(s) }&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;/play/p/KPPpWa7M93d&#34;&gt;playground&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;This implementation does not use pointer receivers.&#xA;So while this is perfectly valid, it would not be usable with the complicated constraint to pointer receivers.&#xA;But it works fine with our &lt;code&gt;InsertAll&lt;/code&gt; version.&#xA;As with many constraints, enforcing that methods use a pointer receiver might actually be overly restrictive for many practical use cases.&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;I hope this illustrates some of the patterns and trade-offs that type parameters on interfaces enable.&#xA;It is a powerful tool, but it also comes with a cost.&#xA;The primary take-aways are:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Use generic interfaces to express constraints on the receiver by using them self-referentially.&lt;/li&gt;&#xA;&lt;li&gt;Use them to create constrained relationships between different type parameters.&lt;/li&gt;&#xA;&lt;li&gt;Use them to abstract over different implementations with different kinds of constraints.&lt;/li&gt;&#xA;&lt;li&gt;When you find yourself in a situation where you need to constrain to pointer receivers, consider whether you can refactor your code to avoid the extra complexity. See &lt;a href=&#34;#should-you-constrain-to-pointer-receivers&#34;&gt;&amp;ldquo;Should you constrain to pointer receivers?&amp;rdquo;&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;As always, do not over-engineer things: a less flexible but simpler and more readable solution may ultimately be the wiser choice.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/fips140&#34;&gt;The FIPS 140-3 Go Cryptographic Module&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/error-syntax&#34;&gt;[ On | No ] syntactic support for error handling&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>[ On | No ] syntactic support for error handling</title><id>tag:blog.golang.org,2013:blog.golang.org/error-syntax</id><link rel="alternate" href="https://go.dev/blog/error-syntax"></link><published>2025-06-03T00:00:00+00:00</published><updated>2025-06-03T00:00:00+00:00</updated><author><name>Robert Griesemer</name></author><summary type="html">Go team plans around error handling support</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/error-syntax&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;[ On | No ] syntactic support for error handling&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Robert Griesemer&lt;br&gt;&#xA;      3 June 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;One of the oldest and most persistent complaints about Go concerns the verbosity of error handling.&#xA;We are all intimately (some may say painfully) familiar with this code pattern:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-Go&#34;&gt;x, err := call()&#xA;if err != nil {&#xA;        // handle err&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The test &lt;code&gt;if err != nil&lt;/code&gt; can be so pervasive that it drowns out the rest of the code.&#xA;This typically happens in programs that do a lot of API calls, and where handling errors&#xA;is rudimentary and they are simply returned.&#xA;Some programs end up with code that looks like this:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-Go&#34;&gt;func printSum(a, b string) error {&#xA;    x, err := strconv.Atoi(a)&#xA;    if err != nil {&#xA;        return err&#xA;    }&#xA;    y, err := strconv.Atoi(b)&#xA;    if err != nil {&#xA;        return err&#xA;    }&#xA;    fmt.Println(&amp;quot;result:&amp;quot;, x + y)&#xA;    return nil&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Of the ten lines of code in this function body, only four (the calls and the last two lines) appear to do real work.&#xA;The remaining six lines come across as noise.&#xA;The verbosity is real, and so it&amp;rsquo;s no wonder that complaints about error handling have topped&#xA;our annual user surveys for years.&#xA;(For a while, the lack of generics surpassed complaints about error handling, but now that&#xA;Go supports generics, error handling is back on top.)&lt;/p&gt;&#xA;&lt;p&gt;The Go team takes community feedback seriously, and so for many years now we have tried to&#xA;come up with a solution for this problem, together with input from the Go community.&lt;/p&gt;&#xA;&lt;p&gt;The first explicit attempt by the Go team dates back to 2018, when Russ Cox&#xA;&lt;a href=&#34;https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;formally described the problem&lt;/a&gt;&#xA;as part of what we called the Go 2 effort at that time.&#xA;He outlined a possible solution based on a&#xA;&lt;a href=&#34;https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;draft design&lt;/a&gt;&#xA;by Marcel van Lohuizen.&#xA;The design was based on a &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;handle&lt;/code&gt; mechanism and was fairly comprehensive.&#xA;The draft includes a detailed analysis of alternative solutions, including comparisons with&#xA;approaches taken by other languages.&#xA;If you&amp;rsquo;re wondering if your particular error handling idea was previously considered,&#xA;read this document!&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-Go&#34;&gt;// printSum implementation using the proposed check/handle mechanism.&#xA;func printSum(a, b string) error {&#xA;    handle err { return err }&#xA;    x := check strconv.Atoi(a)&#xA;    y := check strconv.Atoi(b)&#xA;    fmt.Println(&amp;quot;result:&amp;quot;, x + y)&#xA;    return nil&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;handle&lt;/code&gt; approach was deemed too complicated and almost a year later, in 2019,&#xA;we followed up with the much simplified and by now&#xA;&lt;a href=&#34;/issue/32437#issuecomment-2278932700&#34;&gt;infamous&lt;/a&gt;&#xA;&lt;a href=&#34;https://go.googlesource.com/proposal/+/master/design/32437-try-builtin.md&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;try&lt;/code&gt; proposal&lt;/a&gt;.&#xA;It was based on the ideas of &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;handle&lt;/code&gt;, but the &lt;code&gt;check&lt;/code&gt; pseudo-keyword became&#xA;the &lt;code&gt;try&lt;/code&gt; built-in function and the &lt;code&gt;handle&lt;/code&gt; part was omitted.&#xA;To explore the impact of the &lt;code&gt;try&lt;/code&gt; built-in, we wrote a simple tool&#xA;(&lt;a href=&#34;https://github.com/griesemer/tryhard&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;tryhard&lt;/a&gt;)&#xA;that rewrites existing error handling code using &lt;code&gt;try&lt;/code&gt;.&#xA;The proposal was argued over intensively, approaching 900 comments on the &lt;a href=&#34;/issue/32437&#34;&gt;GitHub issue&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-Go&#34;&gt;// printSum implementation using the proposed try mechanism.&#xA;func printSum(a, b string) error {&#xA;    // use a defer statement to augment errors before returning&#xA;    x := try(strconv.Atoi(a))&#xA;    y := try(strconv.Atoi(b))&#xA;    fmt.Println(&amp;quot;result:&amp;quot;, x + y)&#xA;    return nil&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;However, &lt;code&gt;try&lt;/code&gt; affected control flow by returning from the enclosing function in case of an error,&#xA;and did so from potentially deeply nested expressions, thus hiding this control flow from view.&#xA;This made the proposal unpalatable to many, and despite significant investment&#xA;into this proposal we decided to abandon this effort too.&#xA;In retrospect it might have been better to introduce a new keyword,&#xA;something that we could do now since we have fine-grained control over the language version&#xA;via &lt;code&gt;go.mod&lt;/code&gt; files and file-specific directives.&#xA;Restricting the use of &lt;code&gt;try&lt;/code&gt; to assignments and statements might have alleviated some&#xA;of the other concerns. A &lt;a href=&#34;/issue/73376&#34;&gt;recent proposal&lt;/a&gt; by Jimmy Frasche, which essentially&#xA;goes back to the original &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;handle&lt;/code&gt; design and addresses some of that design&amp;rsquo;s&#xA;shortcomings, pursues that direction.&lt;/p&gt;&#xA;&lt;p&gt;The repercussions of the &lt;code&gt;try&lt;/code&gt; proposal led to much soul searching including a series of blog&#xA;posts by Russ Cox: &lt;a href=&#34;https://research.swtch.com/proposals-intro&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;Thinking about the Go Proposal Process&amp;rdquo;&lt;/a&gt;.&#xA;One conclusion was that we likely diminished our chances for a better outcome by presenting an almost&#xA;fully baked proposal with little space for community feedback and a &amp;ldquo;threatening&amp;rdquo; implementation&#xA;timeline. Per &lt;a href=&#34;https://research.swtch.com/proposals-large&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;Go Proposal Process: Large Changes&amp;rdquo;&lt;/a&gt;:&#xA;&amp;ldquo;in retrospect, &lt;code&gt;try&lt;/code&gt; was a large enough change that the new design we published [&amp;hellip;] should have&#xA;been a second draft design, not a proposal with an implementation timeline&amp;rdquo;.&#xA;But irrespective of a possible process and communication failure in this case, the user sentiment towards&#xA;the proposal was very strongly not in favor.&lt;/p&gt;&#xA;&lt;p&gt;We didn&amp;rsquo;t have a better solution at that time and didn&amp;rsquo;t pursue syntax changes for error handling for several years.&#xA;Plenty of people in the community were inspired, though, and we received a steady trickle&#xA;of error handling proposals, many very similar to each other, some interesting, some incomprehensible,&#xA;and some infeasible.&#xA;To keep track of the expanding landscape, another year later, Ian Lance Taylor created an&#xA;&lt;a href=&#34;/issue/40432&#34;&gt;umbrella issue&lt;/a&gt;&#xA;which summarizes the current state of proposed changes for improved error handling.&#xA;A &lt;a href=&#34;/wiki/Go2ErrorHandlingFeedback&#34;&gt;Go Wiki&lt;/a&gt; was created to collect related feedback, discussions, and articles.&#xA;Independently, other people have started tracking all the many error handling proposals&#xA;over the years.&#xA;It&amp;rsquo;s amazing to see the sheer volume of them all, for instance in Sean K. H. Liao&amp;rsquo;s blog post on&#xA;&lt;a href=&#34;https://seankhliao.com/blog/12020-11-23-go-error-handling-proposals/&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;go error handling proposals&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The complaints about the verbosity of error handling persisted&#xA;(see &lt;a href=&#34;/blog/survey2024-h1-results&#34;&gt;Go Developer Survey 2024 H1 Results&lt;/a&gt;),&#xA;and so, after a series of increasingly refined Go team internal proposals, Ian Lance Taylor published&#xA;&lt;a href=&#34;/issue/71203&#34;&gt;&amp;ldquo;reduce error handling boilerplate using &lt;code&gt;?&lt;/code&gt;&amp;rdquo;&lt;/a&gt; in 2024.&#xA;This time the idea was to borrow from a construct implemented in&#xA;&lt;a href=&#34;https://www.rust-lang.org/&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Rust&lt;/a&gt;, specifically the&#xA;&lt;a href=&#34;https://doc.rust-lang.org/std/result/index.html#the-question-mark-operator-&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;?&lt;/code&gt; operator&lt;/a&gt;.&#xA;The hope was that by leaning on an existing mechanism using an established notation, and taking into&#xA;account what we had learned over the years, we should be able to finally make some progress.&#xA;In small informal user studies where programmers were shown Go code using &lt;code&gt;?&lt;/code&gt;, the vast majority&#xA;of participants correctly guessed the meaning of the code, which further convinced us to give it another&#xA;shot.&#xA;To be able to see the impact of the change, Ian wrote a tool that converts ordinary Go code&#xA;into code that uses the proposed new syntax, and we also prototyped the feature in the&#xA;compiler.&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-Go&#34;&gt;// printSum implementation using the proposed &amp;quot;?&amp;quot; statements.&#xA;func printSum(a, b string) error {&#xA;    x := strconv.Atoi(a) ?&#xA;    y := strconv.Atoi(b) ?&#xA;    fmt.Println(&amp;quot;result:&amp;quot;, x + y)&#xA;    return nil&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Unfortunately, as with the other error handling ideas, this new proposal was also quickly overrun&#xA;with comments and many suggestions for minor tweaks, often based on individual preferences.&#xA;Ian closed the proposal and moved the content into a &lt;a href=&#34;/issue/71460&#34;&gt;discussion&lt;/a&gt;&#xA;to facilitate the conversation and to collect further feedback.&#xA;A slightly modified version was received&#xA;&lt;a href=&#34;https://github.com/golang/go/discussions/71460#discussioncomment-12060294&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;a bit more positively&lt;/a&gt;&#xA;but broad support remained elusive.&lt;/p&gt;&#xA;&lt;p&gt;After so many years of trying, with three full-fledged proposals by the Go team and&#xA;literally &lt;a href=&#34;/issues?q=+is%3Aissue+label%3Aerror-handling&#34;&gt;hundreds&lt;/a&gt; (!)&#xA;of community proposals, most of them variations on a theme,&#xA;all of which failed to attract sufficient (let alone overwhelming) support,&#xA;the question we now face is: how to proceed? Should we proceed at all?&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;We think not.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;To be more precise, we should stop trying to solve the &lt;em&gt;syntactic problem&lt;/em&gt;, at least for the foreseeable&#xA;future.&#xA;The &lt;a href=&#34;https://github.com/golang/proposal?tab=readme-ov-file#consensus-and-disagreement&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;proposal process&lt;/a&gt;&#xA;provides justification for this decision:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The goal of the proposal process is to reach general consensus about the outcome in a timely manner.&#xA;If proposal review cannot identify a general consensus in the discussion of the issue on the issue tracker,&#xA;the usual result is that the proposal is declined.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Furthermore:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;It can happen that proposal review may not identify a general consensus and yet it is clear that the&#xA;proposal should not be outright declined.&#xA;[&amp;hellip;]&#xA;If the proposal review group cannot identify a consensus nor a next step for the proposal,&#xA;the decision about the path forward passes to the Go architects [&amp;hellip;], who review the discussion and&#xA;aim to reach a consensus among themselves.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;None of the error handling proposals reached anything close to a consensus,&#xA;so they were all declined.&#xA;Even the most senior members of the Go team at Google do not unanimously agree&#xA;on the best path forward &lt;em&gt;at this time&lt;/em&gt; (perhaps that will change at some point).&#xA;But without a strong consensus we cannot reasonably move forward.&lt;/p&gt;&#xA;&lt;p&gt;There are valid arguments in favor of the status quo:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;If Go had introduced specific syntactic sugar for error handling early on, few would argue over it today.&#xA;But we are 15 years down the road, the opportunity has passed, and Go has&#xA;a perfectly fine way to handle errors, even if it may seem verbose at times.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Looking from a different angle, let&amp;rsquo;s assume we came across the perfect solution today.&#xA;Incorporating it into the language would simply lead from one unhappy group of users&#xA;(the one that roots for the change) to another (the one that prefers the status quo).&#xA;We were in a similar situation when we decided to add generics to the language, albeit with an&#xA;important difference:&#xA;today nobody is forced to use generics, and good generic libraries are written such that users&#xA;can mostly ignore the fact that they are generic, thanks to type inference.&#xA;On the contrary, if a new syntactic construct for error handling gets added to the language,&#xA;virtually everybody will need to start using it, lest their code become unidiomatic.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Not adding extra syntax is in line with one of Go&amp;rsquo;s design rules:&#xA;do not provide multiple ways of doing the same thing.&#xA;There are exceptions to this rule in areas with high &amp;ldquo;foot traffic&amp;rdquo;: assignments come to mind.&#xA;Ironically, the ability to &lt;em&gt;redeclare&lt;/em&gt; a variable in&#xA;&lt;a href=&#34;/ref/spec#Short_variable_declarations&#34;&gt;short variable declarations&lt;/a&gt; (&lt;code&gt;:=&lt;/code&gt;) was introduced to address a problem&#xA;that arose because of error handling:&#xA;without redeclarations, sequences of error checks require a differently named &lt;code&gt;err&lt;/code&gt; variable for&#xA;each check (or additional separate variable declarations).&#xA;At that time, a better solution might have been to provide more syntactic support for error handling.&#xA;Then, the redeclaration rule may not have been needed, and with it gone, so would be various&#xA;associated &lt;a href=&#34;/issue/377&#34;&gt;complications&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Going back to actual error handling code, verbosity fades into the background if errors are&#xA;actually &lt;em&gt;handled&lt;/em&gt;.&#xA;Good error handling often requires additional information added to an error.&#xA;For instance, a recurring comment in user surveys is about the lack of stack traces associated&#xA;with an error.&#xA;This could be addressed with support functions that produce and return an augmented&#xA;error.&#xA;In this (admittedly contrived) example, the relative amount of boilerplate is much smaller:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-Go&#34;&gt;func printSum(a, b string) error {&#xA;    x, err := strconv.Atoi(a)&#xA;    if err != nil {&#xA;        return fmt.Errorf(&amp;quot;invalid integer: %q&amp;quot;, a)&#xA;    }&#xA;    y, err := strconv.Atoi(b)&#xA;    if err != nil {&#xA;        return fmt.Errorf(&amp;quot;invalid integer: %q&amp;quot;, b)&#xA;    }&#xA;    fmt.Println(&amp;quot;result:&amp;quot;, x + y)&#xA;    return nil&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;New standard library functionality can help reduce error handling boilerplate as well,&#xA;very much in the vein of Rob Pike&amp;rsquo;s 2015 blog post&#xA;&lt;a href=&#34;/blog/errors-are-values&#34;&gt;&amp;ldquo;Errors are values&amp;rdquo;&lt;/a&gt;.&#xA;For instance, in some cases &lt;a href=&#34;/pkg/cmp#Or&#34;&gt;&lt;code&gt;cmp.Or&lt;/code&gt;&lt;/a&gt; may be used to deal with a&#xA;series of errors all at once:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-Go&#34;&gt;func printSum(a, b string) error {&#xA;    x, err1 := strconv.Atoi(a)&#xA;    y, err2 := strconv.Atoi(b)&#xA;    if err := cmp.Or(err1, err2); err != nil {&#xA;        return err&#xA;    }&#xA;    fmt.Println(&amp;quot;result:&amp;quot;, x+y)&#xA;    return nil&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Writing, reading, and debugging code are all quite different activities.&#xA;Writing repeated error checks can be tedious, but today&amp;rsquo;s IDEs provide powerful, even LLM-assisted&#xA;code completion.&#xA;Writing basic error checks is straightforward for these tools.&#xA;The verbosity is most obvious when reading code, but tools might help here as well;&#xA;for instance an IDE with a Go language setting could provide a toggle switch to hide error handling&#xA;code.&#xA;Such switches already exist for other code sections such as function bodies.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;When debugging error handling code, being able to quickly add a &lt;code&gt;println&lt;/code&gt; or&#xA;have a dedicated line or source location for setting a breakpoint in a debugger is helpful.&#xA;This is easy when there is already a dedicated &lt;code&gt;if&lt;/code&gt; statement.&#xA;But if all the error handling logic is hidden behind a &lt;code&gt;check&lt;/code&gt;, &lt;code&gt;try&lt;/code&gt;, or &lt;code&gt;?&lt;/code&gt;, the code may have to&#xA;be changed into an ordinary &lt;code&gt;if&lt;/code&gt; statement first, which complicates debugging&#xA;and may even introduce subtle bugs.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;There are also practical considerations:&#xA;Coming up with a new syntax idea for error handling is cheap;&#xA;hence the proliferation of a multitude of proposals from the community.&#xA;Coming up with a good solution that holds up to scrutiny: not so much.&#xA;It takes a concerted effort to properly design a language change and to actually implement it.&#xA;The real cost still comes afterwards:&#xA;all the code that needs to be changed, the documentation that needs to be updated,&#xA;the tools that need to be adjusted.&#xA;Taken all into account, language changes are very expensive, the Go team is relatively small,&#xA;and there are a lot of other priorities to address.&#xA;(These latter points may change: priorities can shift, team sizes can go up or down.)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;On a final note, some of us recently had the opportunity to attend&#xA;&lt;a href=&#34;https://cloud.withgoogle.com/next/25&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Google Cloud Next 2025&lt;/a&gt;,&#xA;where the Go team had a booth and where we also hosted a small Go Meetup.&#xA;Every single Go user we had a chance to ask was adamant that we should not change the&#xA;language for better error handling.&#xA;Many mentioned that the lack of specific error handling support in Go is most apparent&#xA;when coming freshly from another language that has that support.&#xA;As one becomes more fluent and writes more idiomatic Go code, the issue becomes much less important.&#xA;This is of course not a sufficiently large set of people to be representative,&#xA;but it may be a different set of people than we see on GitHub, and their feedback serves as yet another data point.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Of course, there are also valid arguments in favor of change:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Lack of better error handling support remains the top complaint in our user surveys.&#xA;If the Go team really does take user feedback seriously, we ought to do something about this eventually.&#xA;(Although there does not seem to be&#xA;&lt;a href=&#34;https://github.com/golang/go/discussions/71460#discussioncomment-11977299&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;overwhelming support&lt;/a&gt;&#xA;for a language change either.)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Perhaps the singular focus on reducing the character count is misguided.&#xA;A better approach might be to make default error handling highly visible with a keyword&#xA;while still removing boilerplate (&lt;code&gt;err != nil&lt;/code&gt;).&#xA;Such an approach might make it easier for a reader (a code reviewer!) to see that an error&#xA;is handled, without &amp;ldquo;looking twice&amp;rdquo;, resulting in improved code quality and safety.&#xA;This would bring us back to the beginnings of &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;handle&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We don&amp;rsquo;t really know how much the issue is the straightforward syntactic verbosity of&#xA;error checking, versus the verbosity of good error handling:&#xA;constructing errors that are a useful part of an API and meaningful to developers and&#xA;end-users alike.&#xA;This is something we&amp;rsquo;d like to study in greater depth.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Still, no attempt to address error handling so far has gained sufficient traction.&#xA;If we are honestly taking stock of where we are, we can only admit that we&#xA;neither have a shared understanding of the problem,&#xA;nor do we all agree that there is a problem in the first place.&#xA;With this in mind, we are making the following pragmatic decision:&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;For the foreseeable future, the Go team will stop pursuing syntactic language changes&#xA;for error handling.&#xA;We will also close all open and incoming proposals that concern themselves primarily&#xA;with the syntax of error handling, without further investigation.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;The community has put tremendous effort into exploring, discussing, and debating these issues.&#xA;While this may not have resulted in any changes to error handling syntax, these efforts have&#xA;resulted in many other improvements to the Go language and our processes.&#xA;Maybe, at some point in the future, a clearer picture will emerge on error handling.&#xA;Until then, we look forward to focusing this incredible passion on new opportunities&#xA;to make Go better for everyone.&lt;/p&gt;&#xA;&lt;p&gt;Thank you!&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/generic-interfaces&#34;&gt;Generic interfaces&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/tob-crypto-audit&#34;&gt;Go Cryptography Security Audit&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>Go Cryptography Security Audit</title><id>tag:blog.golang.org,2013:blog.golang.org/tob-crypto-audit</id><link rel="alternate" href="https://go.dev/blog/tob-crypto-audit"></link><published>2025-05-19T00:00:00+00:00</published><updated>2025-05-19T00:00:00+00:00</updated><author><name>Roland Shoemaker and Filippo Valsorda</name></author><summary type="html">Go&amp;#39;s cryptography libraries underwent an audit by Trail of Bits.</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/tob-crypto-audit&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;Go Cryptography Security Audit&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Roland Shoemaker and Filippo Valsorda&lt;br&gt;&#xA;      19 May 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;Go ships with a full suite of cryptography packages in the standard library to help developers build secure applications. Google recently contracted the independent security firm &lt;a href=&#34;https://www.trailofbits.com/&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Trail of Bits&lt;/a&gt; to complete an audit of the core set of packages that are also validated as part of the &lt;a href=&#34;/doc/go1.24#fips140&#34;&gt;new native FIPS 140-3 module&lt;/a&gt;. The audit produced a single low-severity finding, in the legacy and unsupported &lt;a href=&#34;/doc/security/fips140#goboringcrypto&#34;&gt;Go+BoringCrypto integration&lt;/a&gt;, and a handful of informational findings. The full text of the audit report can be found &lt;a href=&#34;https://github.com/trailofbits/publications/blob/d47e8fafa7e3323e5620d228f2f3f3bf58ed5978/reviews/2025-03-google-gocryptographiclibraries-securityreview.pdf&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The scope of the audit included our implementations of key exchange (ECDH and post-quantum ML-KEM), digital signature (ECDSA, RSA, and Ed25519), encryption (AES-GCM, AES-CBC, and AES-CTR), hashing (SHA-1, SHA-2, and SHA-3), key derivation (HKDF and PBKDF2), and authentication (HMAC), as well as the cryptographic random number generator. Low-level big integer and elliptic curve implementations, with their delicate assembly cores, were included. Higher level protocols like TLS and X.509 were not in scope. Three Trail of Bits engineers worked on the audit for a month.&lt;/p&gt;&#xA;&lt;p&gt;We are proud of the security track record of the Go cryptography packages, and of the outcome of this audit, which is just one of many ways we gain assurance of the packages’ correctness. First, we aggressively limit their complexity, guided by the &lt;a href=&#34;/design/cryptography-principles&#34;&gt;Cryptography Principles&lt;/a&gt; which for example prioritize security over performance. Further, we &lt;a href=&#34;https://www.youtube.com/watch?v=lkEH3V3PkS0&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;thoroughly test them&lt;/a&gt; with an array of different techniques. We make a point of leveraging safe APIs even for internal packages, and naturally we can rely on the Go language properties to avoid memory management issues. Finally, we focus on readability to make maintenance easier and code review and audits more effective.&lt;/p&gt;&#xA;&lt;h2 id=&#34;one-low-severity-finding&#34;&gt;One low-severity finding&lt;/h2&gt;&#xA;&lt;p&gt;The only potentially exploitable issue, TOB-GOCL-3, has &lt;em&gt;low severity&lt;/em&gt;, meaning it had minor impact and was difficult to trigger. This issue has been fixed in Go 1.24.&lt;/p&gt;&#xA;&lt;p&gt;Crucially, TOB-GOCL-3 (&lt;a href=&#34;#cgo-memory-management&#34;&gt;discussed further below&lt;/a&gt;) concerns memory management in the &lt;a href=&#34;/doc/security/fips140#goboringcrypto&#34;&gt;legacy Go+BoringCrypto GOEXPERIMENT&lt;/a&gt;, which is not enabled by default and unsupported for use outside of Google.&lt;/p&gt;&#xA;&lt;h2 id=&#34;five-informational-findings&#34;&gt;Five informational findings&lt;/h2&gt;&#xA;&lt;p&gt;The remaining findings are &lt;em&gt;informational&lt;/em&gt;, meaning they do not pose an immediate risk but are relevant to security best practices. We addressed these in the current Go 1.25 development tree.&lt;/p&gt;&#xA;&lt;p&gt;Findings TOB-GOCL-1, TOB-GOCL-2, and TOB-GOCL-6 concern possible timing side-channels in various cryptographic operations. Of these three findings, only TOB-GOCL-2 affects operations that were expected to be constant time due to operating on secret values, but it only affects Power ISA targets (GOARCH ppc64 and ppc64le). TOB-GOCL-4 highlights misuse risk in an internal API, should it be repurposed beyond its current use case. TOB-GOCL-5 points out a missing check for a limit that is impractical to reach.&lt;/p&gt;&#xA;&lt;h2 id=&#34;timing-side-channels&#34;&gt;Timing Side-Channels&lt;/h2&gt;&#xA;&lt;p&gt;Findings TOB-GOCL-1, TOB-GOCL-2, and TOB-GOCL-6 concern minor timing side-channels. TOB-GOCL-1 and TOB-GOCL-6 are related to functions which we do not use for sensitive values, but could be used for such values in the future, and TOB-GOCL-2 is related to the assembly implementation of P-256 ECDSA on Power ISA.&lt;/p&gt;&#xA;&lt;h3 id=&#34;cryptoecdhcryptoecdsa-conversion-from-bytes-to-field-elements-is-not-constant-time-tob-gocl-1&#34;&gt;&lt;code&gt;crypto/ecdh,crypto/ecdsa&lt;/code&gt;: conversion from bytes to field elements is not constant time (TOB-GOCL-1)&lt;/h3&gt;&#xA;&lt;p&gt;The internal implementation of NIST elliptic curves provided a method to convert field elements between an internal and external representation which operated in variable time.&lt;/p&gt;&#xA;&lt;p&gt;All usages of this method operated on public inputs which are not considered secret (public ECDH values, and ECDSA public keys), so we determined that this was not a security issue. That said, we decided to &lt;a href=&#34;/cl/650579&#34;&gt;make the method constant time anyway&lt;/a&gt;, in order to prevent accidentally using this method in the future with secret values, and so that we don&amp;rsquo;t have to think about whether it is an issue or not.&lt;/p&gt;&#xA;&lt;h3 id=&#34;cryptoecdsa-p-256-conditional-negation-is-not-constant-time-in-power-isa-assembly-tob-gocl-2-cve-2025-22866&#34;&gt;&lt;code&gt;crypto/ecdsa&lt;/code&gt;: P-256 conditional negation is not constant time in Power ISA assembly (TOB-GOCL-2, CVE-2025-22866)&lt;/h3&gt;&#xA;&lt;p&gt;Beyond the &lt;a href=&#34;/wiki/PortingPolicy#first-class-ports&#34;&gt;first class Go platforms&lt;/a&gt;, Go also supports a number of additional platforms, including some less common architectures. During the review of our assembly implementations of various underlying cryptographic primitives, the Trail of Bits team found one issue that affected the ECDSA implementation on the ppc64 and ppc64le architectures.&lt;/p&gt;&#xA;&lt;p&gt;Due to the usage of a conditional branching instruction in the implementation of the conditional negation of P-256 points, the function operated in variable-time, rather than constant-time, as expected. The fix for this was relatively simple, &lt;a href=&#34;/cl/643735&#34;&gt;replacing the conditional branching instruction&lt;/a&gt; with a pattern we already use elsewhere to conditionally select the correct result in constant time. We assigned this issue CVE-2025-22866.&lt;/p&gt;&#xA;&lt;p&gt;To prioritize the code that reaches most of our users, and due to the specialized knowledge required to target specific ISAs, we generally rely on community contributions to maintain assembly for non-first class platforms. We thank our partners at IBM for helping provide review for our fix.&lt;/p&gt;&#xA;&lt;h3 id=&#34;cryptoed25519-scalarsetcanonicalbytes-is-not-constant-time-tob-gocl-6&#34;&gt;&lt;code&gt;crypto/ed25519&lt;/code&gt;: Scalar.SetCanonicalBytes is not constant time (TOB-GOCL-6)&lt;/h3&gt;&#xA;&lt;p&gt;The internal edwards25519 package provided a method to convert between an internal and external representation of scalars which operated in variable time.&lt;/p&gt;&#xA;&lt;p&gt;This method was only used on signature inputs to ed25519.Verify, which are not considered secret, so we determined that this was not a security issue. That said, similarly to the TOB-GOCL-1 finding, we decided to &lt;a href=&#34;/cl/648035&#34;&gt;make the method constant time anyway&lt;/a&gt;, in order to prevent accidentally using this method in the future with secret values, and because we are aware that people fork this code outside of the standard library, and may be using it with secret values.&lt;/p&gt;&#xA;&lt;h2 id=&#34;cgo-memory-management&#34;&gt;Cgo Memory Management&lt;/h2&gt;&#xA;&lt;p&gt;Finding TOB-GOCL-3 concerns a memory management issue in the Go+BoringCrypto integration.&lt;/p&gt;&#xA;&lt;h3 id=&#34;cryptoecdh-custom-finalizer-may-free-memory-at-the-start-of-a-c-function-call-using-this-memory-tob-gocl-3&#34;&gt;&lt;code&gt;crypto/ecdh&lt;/code&gt;: custom finalizer may free memory at the start of a C function call using this memory (TOB-GOCL-3)&lt;/h3&gt;&#xA;&lt;p&gt;During the review, there were a number of questions about our cgo-based Go+BoringCrypto integration, which provides a FIPS 140-2 compliant cryptography mode for internal usage at Google. The Go+BoringCrypto code is not supported by the Go team for external use, but has been critical for Google’s internal usage of Go.&lt;/p&gt;&#xA;&lt;p&gt;The Trail of Bits team found one vulnerability and one &lt;a href=&#34;/cl/644120&#34;&gt;non-security relevant bug&lt;/a&gt;, both of which were results of the manual memory management required to interact with a C library. Since the Go team does not support usage of this code outside of Google, we have chosen not to issue a CVE or Go vulnerability database entry for this issue, but we &lt;a href=&#34;/cl/644119&#34;&gt;fixed it in Go 1.24&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This kind of pitfall is one of the many reasons that we decided to move away from the Go+BoringCrypto integration. We have been working on a &lt;a href=&#34;/doc/security/fips140&#34;&gt;native FIPS 140-3 mode&lt;/a&gt; that uses the regular pure Go cryptography packages, allowing us to avoid the complex cgo semantics in favor of the traditional Go memory model.&lt;/p&gt;&#xA;&lt;h2 id=&#34;implementation-completeness&#34;&gt;Implementation Completeness&lt;/h2&gt;&#xA;&lt;p&gt;Findings TOB-GOCL-4 and TOB-GOCL-5 concern limited implementations of two specifications, &lt;a href=&#34;https://csrc.nist.gov/pubs/sp/800/90/a/r1/final&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;NIST SP 800-90A&lt;/a&gt; and &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc8018&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;RFC 8018&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;cryptointernalfips140drbg-ctr-drbg-api-presents-multiple-misuse-risks-tob-gocl-4&#34;&gt;&lt;code&gt;crypto/internal/fips140/drbg&lt;/code&gt;: CTR_DRBG API presents multiple misuse risks (TOB-GOCL-4)&lt;/h3&gt;&#xA;&lt;p&gt;As part of the &lt;a href=&#34;/doc/security/fips140&#34;&gt;native FIPS 140-3 mode&lt;/a&gt; that we are introducing, we needed an implementation of the NIST CTR_DRBG (an AES-CTR based deterministic random bit generator) to provide compliant randomness.&lt;/p&gt;&#xA;&lt;p&gt;Since we only need a small subset of the functionality of the NIST SP 800-90A Rev. 1 CTR_DRBG for our purposes, we did not implement the full specification, in particular omitting the derivation function and personalization strings. These features can be critical to safely use the DRBG in generic contexts.&lt;/p&gt;&#xA;&lt;p&gt;As our implementation is tightly scoped to the specific use case we need, and since the implementation is not publicly exported, we determined that this was acceptable and worth the decreased complexity of the implementation. We do not expect this implementation to ever be used for other purposes internally, and have &lt;a href=&#34;/cl/647815&#34;&gt;added a warning to the documentation&lt;/a&gt; that details these limitations.&lt;/p&gt;&#xA;&lt;h3 id=&#34;cryptopbkdf2-pbkdf2-does-not-enforce-output-length-limitations-tob-gocl-5&#34;&gt;&lt;code&gt;crypto/pbkdf2&lt;/code&gt;: PBKDF2 does not enforce output length limitations (TOB-GOCL-5)&lt;/h3&gt;&#xA;&lt;p&gt;In Go 1.24, we began the process of moving packages from &lt;a href=&#34;https://golang.org/x/crypto&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;golang.org/x/crypto&lt;/a&gt; into the standard library, ending a confusing pattern where first-party, high-quality, and stable Go cryptography packages were kept outside of the standard library for no particular reason.&lt;/p&gt;&#xA;&lt;p&gt;As part of this process we moved the &lt;a href=&#34;https://golang.org/x/crypto/pbkdf2&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;golang.org/x/crypto/pbkdf2&lt;/a&gt; package into the standard library, as crypto/pbkdf2. While reviewing this package, the Trail of Bits team noticed that we did not enforce the limit on the size of derived keys defined in &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc8018&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;RFC 8018&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The limit is &lt;code&gt;(2^32 - 1) * &amp;lt;hash length&amp;gt;&lt;/code&gt;, after which the key would loop. When using SHA-256, exceeding the limit would take a key of more than 137GB. We do not expect anyone has ever used PBKDF2 to generate a key this large, especially because PBKDF2 runs the iterations at every block, but for the sake of correctness, we &lt;a href=&#34;/cl/644122&#34;&gt;now enforce the limit as defined by the standard&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h1 id=&#34;whats-next&#34;&gt;What’s Next&lt;/h1&gt;&#xA;&lt;p&gt;The results of this audit validate the effort the Go team has put into developing high-quality, easy to use cryptography libraries and should provide confidence to our users who rely on them to build safe and secure software.&lt;/p&gt;&#xA;&lt;p&gt;We’re not resting on our laurels, though: the Go contributors are continuing to develop and improve the cryptography libraries we provide users.&lt;/p&gt;&#xA;&lt;p&gt;Go 1.24 now includes a FIPS 140-3 mode written in pure Go, which is currently undergoing CMVP testing. This will provide a supported FIPS 140-3 compliant mode for all users of Go, replacing the currently unsupported Go+BoringCrypto integration.&lt;/p&gt;&#xA;&lt;p&gt;We are also working to implement modern post-quantum cryptography, introducing a ML-KEM-768 and ML-KEM-1024 implementation in Go 1.24 in the &lt;a href=&#34;/pkg/crypto/mlkem&#34;&gt;crypto/mlkem package&lt;/a&gt;, and adding support to the crypto/tls package for the hybrid X25519MLKEM768 key exchange.&lt;/p&gt;&#xA;&lt;p&gt;Finally, we are planning on introducing new easier to use high-level cryptography APIs, designed to reduce the barrier for picking and using high-quality algorithms for basic use cases. We plan to begin with offering a simple password hashing API that removes the need for users to decide which of the myriad of possible algorithms they should be relying on, with mechanisms to automatically migrate to newer algorithms as the state-of-the-art changes.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/error-syntax&#34;&gt;[ On | No ] syntactic support for error handling&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/testing-b-loop&#34;&gt;More predictable benchmarking with testing.B.Loop&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry><entry><title>More predictable benchmarking with testing.B.Loop</title><id>tag:blog.golang.org,2013:blog.golang.org/testing-b-loop</id><link rel="alternate" href="https://go.dev/blog/testing-b-loop"></link><published>2025-04-02T00:00:00+00:00</published><updated>2025-04-02T00:00:00+00:00</updated><author><name>Junyang Shao</name></author><summary type="html">Better benchmark looping in Go 1.24.</summary><content type="html">&#xA;&lt;div id=&#34;blog&#34;&gt;&lt;div id=&#34;content&#34;&gt;&#xA;  &lt;div id=&#34;content&#34;&gt;&#xA;&#xA;    &lt;div class=&#34;Article&#34; data-slug=&#34;/blog/testing-b-loop&#34;&gt;&#xA;    &#xA;    &lt;h1 class=&#34;small&#34;&gt;&lt;a href=&#34;/blog/&#34;&gt;The Go Blog&lt;/a&gt;&lt;/h1&gt;&#xA;    &#xA;&#xA;    &lt;h1&gt;More predictable benchmarking with testing.B.Loop&lt;/h1&gt;&#xA;      &#xA;      &lt;p class=&#34;author&#34;&gt;&#xA;      Junyang Shao&lt;br&gt;&#xA;      2 April 2025&#xA;      &lt;/p&gt;&#xA;      &#xA;      &lt;div class=&#39;markdown&#39;&gt;&#xA;&lt;p&gt;Go developers who have written benchmarks using the&#xA;&lt;a href=&#34;https://pkg.go.dev/testing&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;testing&lt;/code&gt;&lt;/a&gt; package might have encountered some of&#xA;its various pitfalls. Go 1.24 introduces a new way to write benchmarks that&amp;rsquo;s just&#xA;as easy to use, but at the same time far more robust:&#xA;&lt;a href=&#34;https://pkg.go.dev/testing#B.Loop&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;testing.B.Loop&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Traditionally, Go benchmarks are written using a loop from 0 to &lt;code&gt;b.N&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func Benchmark(b *testing.B) {&#xA;  for range b.N {&#xA;    ... code to measure ...&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Using &lt;code&gt;b.Loop&lt;/code&gt; instead is a trivial change:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func Benchmark(b *testing.B) {&#xA;  for b.Loop() {&#xA;    ... code to measure ...&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;testing.B.Loop&lt;/code&gt; has many benefits:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;It prevents unwanted compiler optimizations within the benchmark loop.&lt;/li&gt;&#xA;&lt;li&gt;It automatically excludes setup and cleanup code from benchmark timing.&lt;/li&gt;&#xA;&lt;li&gt;Code can&amp;rsquo;t accidentally depend on the total number of iterations or the current&#xA;iteration.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;These were all easy mistakes to make with &lt;code&gt;b.N&lt;/code&gt;-style benchmarks that would&#xA;silently result in bogus benchmark results. As an added bonus, &lt;code&gt;b.Loop&lt;/code&gt;-style&#xA;benchmarks even complete in less time!&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s explore the advantages of &lt;code&gt;testing.B.Loop&lt;/code&gt; and how to effectively utilize it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;old-benchmark-loop-problems&#34;&gt;Old benchmark loop problems&lt;/h2&gt;&#xA;&lt;p&gt;Before Go 1.24, while the basic structure of a benchmark was simple, more sophisticated&#xA;benchmarks required more care:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func Benchmark(b *testing.B) {&#xA;  ... setup ...&#xA;  b.ResetTimer() // if setup may be expensive&#xA;  for range b.N {&#xA;    ... code to measure ...&#xA;    ... use sinks or accumulation to prevent dead-code elimination ...&#xA;  }&#xA;  b.StopTimer() // if cleanup or reporting may be expensive&#xA;  ... cleanup ...&#xA;  ... report ...&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If setup or cleanup are non-trivial, the developer needs to surround the benchmark loop&#xA;with &lt;code&gt;ResetTimer&lt;/code&gt; and/or &lt;code&gt;StopTimer&lt;/code&gt; calls. These are easy to forget, and even if the&#xA;developer remembers they may be necessary, it can be difficult to judge whether setup or&#xA;cleanup are &amp;ldquo;expensive enough&amp;rdquo; to require them.&lt;/p&gt;&#xA;&lt;p&gt;Without these, the &lt;code&gt;testing&lt;/code&gt; package can only time the entire benchmark function. If a&#xA;benchmark function omits them, the setup and cleanup code will be included in the overall&#xA;time measurement, silently skewing the final benchmark result.&lt;/p&gt;&#xA;&lt;p&gt;There is another, more subtle pitfall that requires deeper understanding:&#xA;(&lt;a href=&#34;https://eli.thegreenplace.net/2023/common-pitfalls-in-go-benchmarking/&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Example source&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func isCond(b byte) bool {&#xA;  if b%3 == 1 &amp;amp;&amp;amp; b%7 == 2 &amp;amp;&amp;amp; b%17 == 11 &amp;amp;&amp;amp; b%31 == 9 {&#xA;    return true&#xA;  }&#xA;  return false&#xA;}&#xA;&#xA;func BenchmarkIsCondWrong(b *testing.B) {&#xA;  for range b.N {&#xA;    isCond(201)&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In this example, the user might observe &lt;code&gt;isCond&lt;/code&gt; executing in sub-nanosecond&#xA;time. CPUs are fast, but not that fast! This seemingly anomalous result stems&#xA;from the fact that &lt;code&gt;isCond&lt;/code&gt; is inlined, and since its result is never used, the&#xA;compiler eliminates it as dead code. As a result, this benchmark doesn&amp;rsquo;t measure &lt;code&gt;isCond&lt;/code&gt;&#xA;at all; it measures how long it takes to do nothing. In this case, the sub-nanosecond&#xA;result is a clear red flag, but in more complex benchmarks, partial dead-code elimination&#xA;can lead to results that look reasonable but still aren&amp;rsquo;t measuring what was intended.&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-testingbloop-helps&#34;&gt;How &lt;code&gt;testing.B.Loop&lt;/code&gt; helps&lt;/h2&gt;&#xA;&lt;p&gt;Unlike a &lt;code&gt;b.N&lt;/code&gt;-style benchmark, &lt;code&gt;testing.B.Loop&lt;/code&gt; is able to track when it is first called&#xA;in a benchmark when the final iteration ends. The &lt;code&gt;b.ResetTimer&lt;/code&gt; at the loop&amp;rsquo;s start&#xA;and &lt;code&gt;b.StopTimer&lt;/code&gt; at its end are integrated into &lt;code&gt;testing.B.Loop&lt;/code&gt;, eliminating the need&#xA;to manually manage the benchmark timer for setup and cleanup code.&lt;/p&gt;&#xA;&lt;p&gt;Furthermore, the Go compiler now detects loops where the condition is just a call to&#xA;&lt;code&gt;testing.B.Loop&lt;/code&gt; and prevents dead code elimination within the loop. In Go 1.24, this is&#xA;implemented by disallowing inlining into the body of such a loop, but we plan to&#xA;&lt;a href=&#34;/issue/73137&#34;&gt;improve&lt;/a&gt; this in the future.&lt;/p&gt;&#xA;&lt;p&gt;Another nice feature of &lt;code&gt;testing.B.Loop&lt;/code&gt; is its one-shot ramp-up approach. With a &lt;code&gt;b.N&lt;/code&gt;-style&#xA;benchmark, the testing package must call the benchmark function several times with different&#xA;values of &lt;code&gt;b.N&lt;/code&gt;, ramping up until the measured time reached a threshold. In contrast, &lt;code&gt;b.Loop&lt;/code&gt;&#xA;can simply run the benchmark loop until it reaches the time threshold, and only needs to call&#xA;the benchmark function once. Internally, &lt;code&gt;b.Loop&lt;/code&gt; still uses a ramp-up process to amortize&#xA;measurement overhead, but this is hidden from the caller and can be more efficient.&lt;/p&gt;&#xA;&lt;p&gt;Certain constraints of the &lt;code&gt;b.N&lt;/code&gt;-style loop still apply to the &lt;code&gt;b.Loop&lt;/code&gt;-style&#xA;loop. It remains the user&amp;rsquo;s responsibility to manage the timer within the benchmark loop,&#xA;when necessary:&#xA;(&lt;a href=&#34;https://eli.thegreenplace.net/2023/common-pitfalls-in-go-benchmarking/&#34; rel=&#34;noreferrer&#34; target=&#34;_blank&#34;&gt;Example source&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func BenchmarkSortInts(b *testing.B) {&#xA;  ints := make([]int, N)&#xA;  for b.Loop() {&#xA;    b.StopTimer()&#xA;    fillRandomInts(ints)&#xA;    b.StartTimer()&#xA;    slices.Sort(ints)&#xA;  }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In this example, to benchmark the in-place sorting performance of &lt;code&gt;slices.Sort&lt;/code&gt;, a&#xA;randomly initialized array is required for each iteration. The user must still&#xA;manually manage the timer in such cases.&lt;/p&gt;&#xA;&lt;p&gt;Furthermore, there still needs to be exactly one such loop in the benchmark function body&#xA;(a &lt;code&gt;b.N&lt;/code&gt;-style loop cannot coexist with a &lt;code&gt;b.Loop&lt;/code&gt;-style loop), and every iteration of the&#xA;loop should do the same thing.&lt;/p&gt;&#xA;&lt;h2 id=&#34;when-to-use&#34;&gt;When to use&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;code&gt;testing.B.Loop&lt;/code&gt; method is now the preferred way to write benchmarks:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;func Benchmark(b *testing.B) {&#xA;  ... setup ...&#xA;  for b.Loop() {&#xA;    // optional timer control for in-loop setup/cleanup&#xA;    ... code to measure ...&#xA;  }&#xA;  ... cleanup ...&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;testing.B.Loop&lt;/code&gt; offers faster, more accurate, and&#xA;more intuitive benchmarking.&lt;/p&gt;&#xA;&lt;h2 id=&#34;acknowledgements&#34;&gt;Acknowledgements&lt;/h2&gt;&#xA;&lt;p&gt;A huge thank you to everyone in the community who provided feedback on the proposal&#xA;issue and reported bugs as this feature was released! I&amp;rsquo;m also grateful to Eli&#xA;Bendersky for his helpful blog summaries. And finally a big thank you to Austin Clements,&#xA;Cherry Mui and Michael Pratt for their review, thoughtful work on the design options and&#xA;documentation improvements. Thank you all for your contributions!&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&#xA;    &lt;/div&gt;&#xA;&#xA;    &#xA;    &lt;div class=&#34;Article prevnext&#34;&gt;&#xA;    &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;        &lt;p&gt;&#xA;        &#xA;          &#xA;            &lt;b&gt;Next article: &lt;/b&gt;&lt;a href=&#34;/blog/tob-crypto-audit&#34;&gt;Go Cryptography Security Audit&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &#xA;          &#xA;            &lt;b&gt;Previous article: &lt;/b&gt;&lt;a href=&#34;/blog/coretypes&#34;&gt;Goodbye core types - Hello Go as we know and love it!&lt;/a&gt;&lt;br&gt;&#xA;          &#xA;        &#xA;        &lt;b&gt;&lt;a href=&#34;/blog/all&#34;&gt;Blog Index&lt;/a&gt;&lt;/b&gt;&#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;      &#xA;    &#xA;    &lt;/div&gt;&#xA;    &#xA;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;script src=&#34;/js/play.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;</content></entry></feed>

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid Atom 1.0" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=http%3A//blog.golang.org/feed.atom

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda