Published · 6h agoBuild6 min read
Kubernetes 1.35.0 and Go 1.27: the API held, the behavior moved
A liveness probe that fires too early and a JSON package rebuilt underneath its own import path both pass every check you own. The first symptom is a restart count, not an error.
Written for builders.See today for builders

What happened
- Kubernetes has three probe types: startup probes determine whether the application inside the container has started, readiness probes determine whether it is ready to receive traffic, and liveness probes determine whether the container needs to be restarted.
- Probes are sent by the kubelet; each node in the cluster has its own kubelet, whose job is to make sure the right pods are running and being probed for that node.
- An httpGet probe sends a request every periodSeconds and is allowed to fail failureThreshold consecutive times before Kubernetes kills the container; status codes 200-399 count as a success.
- By default the CrashLoopBackOff delay is 10 seconds, doubling with each crash up to a maximum wait of 5 minutes (the author shortened it to 3 seconds for the demo).
- Without probes, Kubernetes considers a container Ready as soon as it starts, even though it is still doing startup work and not yet listening on its port.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
A startup probe exists to keep the liveness probe from firing at the wrong moment. That is the reason the three are separate at all: the startup probe asks whether the application inside the container has come up, the readiness probe asks whether it should be sent traffic, and the liveness probe asks whether the container should be killed and restarted [1]. Only the third one has teeth.
A liveness probe that runs before the startup probe has succeeded, then, is not a monitoring inaccuracy. It is a kill order against a process that is still initialising, and the kubelet on the node is what carries it out [2]. Probes do not act on a single miss: the default failureThreshold is 3 and the default successThreshold is 1, and after that many consecutive failures the container is killed [3][12].
Then the arithmetic takes over. CrashLoopBackOff starts at 10 seconds and doubles with each crash up to a ceiling of 5 minutes [4]. Walk it: 10, 20, 40, 80, 160, and the next doubling would be 320, so the ceiling binds from the sixth restart on [1]. The first five waits add up to 310 seconds, a little over five minutes of nothing happening [2]. Once the ceiling binds, the pod gets at most twelve start attempts an hour [3], each one closing out a kill that has a default termination grace period of 30 seconds in front of it [12]. If the application needs longer to initialise than the early liveness probe tolerates, every cycle manufactures the condition that caused it. That is the mechanism behind DevOps'ish's description of this as the failure that makes a slow-starting service restart forever [14].
What it cost to see it
The person who found this was not running a conformance suite. He was writing a blog post about probes, and to make the demos interactive he built webernetes, a partial port of Kubernetes to TypeScript carrying more than 100,000 lines of ported Go so a simulated cluster runs in the browser [8]. He then checked the simulator's behavior against k3s, and in the process turned up a bug in Kubernetes itself [9].
Worth being precise about who says what. The post as supplied states only that the author verified against k3s and found a bug [9]. The specifics, that the fault is liveness probes firing before the startup probe has succeeded, that it was reproduced on k3s, minikube and kind, and that it was introduced in v1.35.0, come from Chris Short's summary in DevOps'ish [13].
Hold those two facts next to each other. Adopting v1.35.0 is a string change. Establishing that v1.35.0 changed pod restart behavior took a simulator, a reference cluster, and reproduction across three distributions [8][9][13]. The manifest does not move: the same YAML that worked before is the YAML that now loops, because the probe configuration is not what changed [13]. Nothing in an API review catches that, which is why the regression reached a release and was caught by someone outside the project writing an explainer.
The same move in Go 1.27
Go 1.27's standard library does structurally the same thing, deliberately and in the open. encoding/json/v2 arrives as a new package with configurable options and stricter defaults, alongside encoding/json/jsontext for low-level streaming [22]. The part that touches code nobody is going to edit is the sentence after it: the existing encoding/json package is now backed by the v2 implementation, for faster unmarshaling, while maintaining backwards compatibility, per the Go team [23]. The import path is unchanged, the API is unchanged, the engine underneath is not. The compiler has nothing to say about it.
The performance framing is worth reading at full precision too. The release notes put size-specialized allocation at up to 30% off small object allocation costs, where small means under 80 bytes, and about 1% better overall for allocation-heavy programs [24]. The headline figure is roughly thirty times the whole-program figure [4], and the summary that most people will actually read carried the 30% without either the size bound or the 1% [18]. That gap is not a marketing complaint, it is a measurement problem: if a runtime change is worth about 1% end to end, a genuine regression of the same order in your own hot path sits inside the noise you have already agreed to accept as an upgrade benefit.
The language work in the release is additive rather than substitutive, and that is the point of contrast. Methods can now take type parameters, so math/rand/v2 can offer one generic N over integer types instead of a method per type [19]. Struct literal keys may be any valid field selector, letting nested and embedded fields be set directly [20]. Type inference now applies in composite literals, type conversions and channel sends [21]. None of that breaks a build; all of it invites diffs. The serialization swap breaks no build either, and invites none.
Even the release date needs a source. The Go blog announcement dates itself only as "Today" [34]; the 19 August 2026 ship date comes from DevOps'ish [15].
The instruments arrived in the same release
Go shipped diagnostics alongside the substitution, which is the honest read on how much confidence the swap deserves. The goroutineleak profile in runtime/pprof is generally available, detecting permanently blocked goroutines automatically [25]. net/http/httptest gains NewTestServer, an in-memory fake network meant for use with testing/synctest [26]. Both target exactly the class of defect that presents as intermittency rather than failure.
Kubernetes has no equivalent on offer here, and the reason is uncomfortable: the probes are simultaneously the diagnostic and the failure surface. A container without a startup probe is treated as Ready the instant it starts, even while it is still initialising and not yet listening [5]. Adding a startup probe inverts that, holding the pod not-Ready until the first success [6]. So the mitigation for the 1.35.0 behavior is the same subsystem that mis-sequences under it. And readiness only protects traffic that respects it: a client addressing a pod's IP directly bypasses the readiness mechanism entirely and will keep hitting a starting container [7]. The Ready condition itself is tri-state, True, False or Unknown [11], which is a reminder that the signal your dashboard renders as a green dot has three values and a race.
Substitution as the normal case
Docker is running the same play with more marketing around it. Docker VMM is a new in-house virtualization layer, in beta with Docker Desktop v4.86 on Windows and macOS, with Linux arriving at general availability [30], targeted for October 2026 [32]. It replaces libkrun on Apple hardware, Hyper-V or WSL on Windows, and KVM with QEMU on Linux, an arrangement the company says produced minor inconsistencies and hiccups, and which the unified layer is claimed to minimize [31]. Keep the contract, replace the implementation, characterise every resulting difference as an improvement. That is the same operation as backing encoding/json with v2, and the same operation that shipped a liveness sequencing change in a patch-versioned Kubernetes minor release [13][23].
The practical consequence is narrow and worth internalising. A green pipeline certifies the interface: it compiles, the API checks pass, the manifests validate. It does not certify the ordering of two probes inside a kubelet, and it does not certify that your structs round-trip through a rewritten encoder the way they did last week. The cost of adopting a behavior change is one line in a file. The cost of proving one was published for you this week: a hundred thousand lines of ported Go and three cluster distributions [8][13].
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
Kubernetes has three probe types: startup probes determine whether the application inside the container has started, readiness probes determine whether it is ready to receive traffic, and liveness probes determine whether the container needs to be restarted.
ReportedView cited source - [2]
Probes are sent by the kubelet; each node in the cluster has its own kubelet, whose job is to make sure the right pods are running and being probed for that node.
ReportedView cited source - [3]
An httpGet probe sends a request every periodSeconds and is allowed to fail failureThreshold consecutive times before Kubernetes kills the container; status codes 200-399 count as a success.
ReportedView cited source - [4]
By default the CrashLoopBackOff delay is 10 seconds, doubling with each crash up to a maximum wait of 5 minutes (the author shortened it to 3 seconds for the demo).
ReportedView cited source - [5]
Without probes, Kubernetes considers a container Ready as soon as it starts, even though it is still doing startup work and not yet listening on its port.
ReportedView cited source - [6]
NotReady is the default for pods with containers that have a startup probe; the pod only becomes Ready after the first startup probe succeeds.
ReportedView cited source
Sources & coverage · 10 publishers
The reporting this story was synthesized from, earliest first. Every link goes to the original.
- blog.golang.orgNicholas Husin, on behalf of the Go team4d agoGo 1.27 is released
- cloudnativenow.com14h ago

