Problem
waitForGangTestPods treats every error from its pod Get as a hard, non-retryable failure:
// validators/conformance/gang_scheduling_check.go
pod, err := clientset.CoreV1().Pods(run.namespace).Get(ctx, run.pods[i], metav1.GetOptions{})
if err != nil {
return false, errors.Wrap(errors.ErrCodeInternal,
fmt.Sprintf("failed to get gang test pod %s", run.pods[i]), err)
}
Returning a non-nil error from a wait.PollUntilContextCancel condition aborts the poll immediately. So a single throttled read ends the check, even though the very next poll interval would have succeeded.
On a loaded cluster that read gets throttled by client-go's own rate limiter, and the check fails with:
[TIMEOUT] gang test pods did not complete in time: [INTERNAL] failed to get gang test pod gang-worker-<id>-0:
client rate limiter Wait returned an error: context deadline exceeded
This is client-side throttling inside the validator, not a cluster fault.
Why it is a false negative
Observed on GB300 EKS while validating #2382. The check had already succeeded at everything it actually tests:
- both KAI CRDs present
podgroup-controller and queue-controller both 1/1 Running
- the PodGroup and both test pods created successfully in
gang-scheduling-test-<suffix>
default-parent-queue / default-queue present
It then failed while polling. An identical re-run on the same cluster passed. Nothing about gang scheduling was broken — the check reported a healthy cluster as failing.
The fix already exists, it is just not wired here
The repo has a shared classifier for exactly this error. ClassifyK8sReadError maps context, apiserver, transport, and rate-limiter-deadline timeouts to ErrCodeTimeout, and helpers_test.go explicitly pins the case:
name: "client-go rate limiter deadline (plain-string chain)",
err: fmt.Errorf("client rate limiter Wait returned an error: %w", ...)
But it is wired into only some read sites — dra_support_check.go (2), helpers.go (1), and the secure-access claim read. gang_scheduling_check.go does not reference it at all:
$ grep -c classifyK8sReadError validators/conformance/gang_scheduling_check.go
0
Suggested fix
Route the pod Get through classifyK8sReadError, and let the poll treat a classified timeout as retryable — return (false, nil) to poll again — so only the enclosing GangTestPodTimeout decides when to give up. Reserve a hard error for genuinely terminal cases.
Worth auditing the other polling loops in validators/conformance/ for the same shape, since the classifier exists but adoption is partial.
Scope
Not specific to any recipe. The check runs on 29 recipes across every accelerator and service, so the flake is cluster-load dependent rather than platform dependent, and gets likelier as the catalog and cluster size grow.
Related: #1513 (closed by #1514) is the same bug, one step earlier
#1513 — "gang-scheduling conformance check flakes on transient KAI admission unavailability" — hit this same check with the same underlying shape: a read that could not land treated as a terminal verdict.
There it was step 1, where an instantaneous getDeploymentIfAvailable failed the whole phase on a single-replica blip:
[NOT_FOUND] KAI scheduler component admission check failed:
[INTERNAL] deployment kai-scheduler/admission not available: 0/1 replicas
Its corrective action was to replace the instantaneous read with a bounded readiness wait — poll until available or hit the timeout, so a transient blip is tolerated while a genuinely-down deployment still fails closed after the bound.
This issue is the identical fix one step later in the same function. #1513 hardened step 1 (deployment readiness); the pod poll in waitForGangTestPods still aborts on the first failed read. The remedy has the same shape: let the enclosing timeout decide the verdict, not a single unlucky API call.
Two things follow from that:
Origin
Surfaced during GB300 EKS validation for #2382. Not blocking that PR — both leaves validate green, and the re-run passed.
Problem
waitForGangTestPodstreats every error from its podGetas a hard, non-retryable failure:Returning a non-nil error from a
wait.PollUntilContextCancelcondition aborts the poll immediately. So a single throttled read ends the check, even though the very next poll interval would have succeeded.On a loaded cluster that read gets throttled by client-go's own rate limiter, and the check fails with:
This is client-side throttling inside the validator, not a cluster fault.
Why it is a false negative
Observed on GB300 EKS while validating #2382. The check had already succeeded at everything it actually tests:
podgroup-controllerandqueue-controllerboth1/1 Runninggang-scheduling-test-<suffix>default-parent-queue/default-queuepresentIt then failed while polling. An identical re-run on the same cluster passed. Nothing about gang scheduling was broken — the check reported a healthy cluster as failing.
The fix already exists, it is just not wired here
The repo has a shared classifier for exactly this error.
ClassifyK8sReadErrormaps context, apiserver, transport, and rate-limiter-deadline timeouts toErrCodeTimeout, andhelpers_test.goexplicitly pins the case:But it is wired into only some read sites —
dra_support_check.go(2),helpers.go(1), and the secure-access claim read.gang_scheduling_check.godoes not reference it at all:Suggested fix
Route the pod
GetthroughclassifyK8sReadError, and let the poll treat a classified timeout as retryable — return(false, nil)to poll again — so only the enclosingGangTestPodTimeoutdecides when to give up. Reserve a hard error for genuinely terminal cases.Worth auditing the other polling loops in
validators/conformance/for the same shape, since the classifier exists but adoption is partial.Scope
Not specific to any recipe. The check runs on 29 recipes across every accelerator and service, so the flake is cluster-load dependent rather than platform dependent, and gets likelier as the catalog and cluster size grow.
Related: #1513 (closed by #1514) is the same bug, one step earlier
#1513 — "gang-scheduling conformance check flakes on transient KAI admission unavailability" — hit this same check with the same underlying shape: a read that could not land treated as a terminal verdict.
There it was step 1, where an instantaneous
getDeploymentIfAvailablefailed the whole phase on a single-replica blip:Its corrective action was to replace the instantaneous read with a bounded readiness wait — poll until available or hit the timeout, so a transient blip is tolerated while a genuinely-down deployment still fails closed after the bound.
This issue is the identical fix one step later in the same function. #1513 hardened step 1 (deployment readiness); the pod poll in
waitForGangTestPodsstill aborts on the first failed read. The remedy has the same shape: let the enclosing timeout decide the verdict, not a single unlucky API call.Two things follow from that:
classifyK8sReadErrornoted above suggests it did.Origin
Surfaced during GB300 EKS validation for #2382. Not blocking that PR — both leaves validate green, and the re-run passed.