k3s-io/k3s · warning
apiserver not ready
Error message
apiserver not ready
What it means
ErrAPINotReady (pkg/util/apierrors.go) is sent as HTTP 503 by handlers.APIServer when a request to the proxied kube-apiserver routes (/k8s/... on the supervisor port) arrives but control.Runtime.APIServer is nil - the apiserver handler has not been installed yet. It marks the startup window or a failed apiserver launch, and util.IsAPIServerError treats it (and ErrAPIDisabled) specially for retry logic.
Source
Thrown at pkg/util/apierrors.go:18
package util
import (
"crypto/rand"
"errors"
"fmt"
"math/big"
"net/http"
"github.com/k3s-io/api/pkg/generated/clientset/versioned/scheme"
"github.com/sirupsen/logrus"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
)
var ErrAPINotReady = errors.New("apiserver not ready")
var ErrAPIDisabled = errors.New("apiserver disabled")
var ErrCoreNotReady = errors.New("runtime core not ready")
// SendErrorWithID sends and logs a random error ID so that logs can be correlated
// between the REST API (which does not provide any detailed error output, to avoid
// information disclosure) and the server logs.
func SendErrorWithID(err error, component string, resp http.ResponseWriter, req *http.Request, status ...int) {
errID, _ := rand.Int(rand.Reader, big.NewInt(99999))
logrus.Errorf("%s error ID %05d: %v", component, errID, err)
SendError(fmt.Errorf("%s error ID %05d", component, errID), resp, req, status...)
}
// SendError sends a properly formatted error response
func SendError(err error, resp http.ResponseWriter, req *http.Request, status ...int) {
var code int
if len(status) == 1 {
code = status[0]
}View on GitHub (pinned to 6ba341e396)
Solutions
- Retry with backoff until /readyz (or the supervisor's readyz route) succeeds - this error is expected to be transient.
- If it persists, check k3s logs for kube-apiserver startup failures (bad --kube-apiserver-arg, cert problems, etcd unavailable).
- Point clients at a load balancer that health-checks /readyz so unready servers are skipped.
- Verify disk/CPU headroom on the server; slow etcd delays apiserver readiness.
Example fix
# before: one-shot call may hit 503 apiserver not ready curl -sk https://127.0.0.1:6443/k8s/version # after: gate on readiness until curl -sk https://127.0.0.1:6443/readyz >/dev/null; do sleep 2; done curl -sk https://127.0.0.1:6443/k8s/version
Defensive patterns
Strategy: retry
Validate before calling
# Gate any /k8s call on readiness first until curl -sk https://127.0.0.1:6443/readyz >/dev/null 2>&1; do sleep 2; done
Try / catch
if errors.Is(err, util.ErrAPINotReady) || resp.StatusCode == http.StatusServiceUnavailable {
// startup window: retry with backoff; escalate only after readyz stays green and calls still fail
} Prevention
- In Go clients, use util.IsAPIServerError-style checks (errors.Is against ErrAPINotReady) to classify 503s.
- Front supervisors with an LB health-checked on /readyz.
- Give slow control planes minutes, not seconds, before declaring failure.
When it happens
Trigger: Hitting the supervisor's apiserver proxy route before kube-apiserver finished initializing, or after apiserver startup failed so Runtime.APIServer was never set. Agents and clients using the supervisor port as their kube-apiserver endpoint see this during early startup.
Common situations: Scripts that target 6443 immediately after k3s starts; first-boot joins; control planes slow under load (etcd compaction, disk pressure) so apiserver init takes minutes.
Related errors
- apiserver disabled
- failed to start wranger controllers
- no bootstrap data is available to reconcile against
- this server has not yet been promoted from learner to voting
- server node name not set
AI-assisted analysis of k3s-io/k3s@6ba341e396 (2026-08-15).
Data as JSON: /api/errors/40b2b34fbf1c3b3b.
Report an issue: GitHub.