GoogleContainerTools/skaffold · error

STATUSCHECK_UNKNOWN_UNSCHEDULABLE

STATUSCHECK_UNKNOWN_UNSCHEDULABLE

Error message

%s: %s

What it means

This error (code STATUSCHECK_UNKNOWN_UNSCHEDULABLE) is produced when a pod cannot be scheduled and the scheduler's rejection message does not match any known taint pattern Skaffold understands. The scheduler reason and message are passed through verbatim so the underlying scheduling failure is still visible.

Source

Thrown at pkg/diag/validator/validator.go:233

	// See https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-states
	for _, c := range cs {
		switch {
		case c.State.Waiting != nil:
			return extractErrorMessageFromWaitingContainerStatus(po, c)
		case c.State.Terminated != nil && c.State.Terminated.ExitCode != 0:
			sc, l := getPodLogs(po, c.Name, proto.StatusCode_STATUSCHECK_CONTAINER_TERMINATED)
			return sc, l, fmt.Errorf("container %s terminated with exit code %d", c.Name, c.State.Terminated.ExitCode)
		}
	}
	// No waiting or terminated containers, pod should be in good health.
	return proto.StatusCode_STATUSCHECK_SUCCESS, nil, nil
}

func getUntoleratedTaints(reason string, message string) (proto.StatusCode, error) {
	matches := taintsRe.FindAllStringSubmatch(message, -1)
	errCode := proto.StatusCode_STATUSCHECK_UNKNOWN_UNSCHEDULABLE
	if len(matches) == 0 {
		return errCode, fmt.Errorf("%s: %s", reason, message)
	}
	messages := make([]string, len(matches))
	// TODO: Add actionable item to fix these errors.
	for i, m := range matches {
		if len(m) < 2 {
			continue
		}
		t := m[1]
		switch t {
		case v1.TaintNodeMemoryPressure:
			messages[i] = "1 node has memory pressure"
			errCode = proto.StatusCode_STATUSCHECK_NODE_MEMORY_PRESSURE
		case v1.TaintNodeDiskPressure:
			messages[i] = "1 node has disk pressure"
			errCode = proto.StatusCode_STATUSCHECK_NODE_DISK_PRESSURE
		case v1.TaintNodePIDPressure:
			messages[i] = "1 node has PID pressure"
			errCode = proto.StatusCode_STATUSCHECK_NODE_PID_PRESSURE

View on GitHub (pinned to a1189de023)

Solutions

  1. Read the scheduler message (kubectl describe pod → Events) for the concrete reason (e.g. 'Insufficient cpu', 'node(s) didn't match nodeSelector').
  2. Lower resource requests or add capacity if it is a resources issue (kubectl describe nodes).
  3. Fix nodeSelector/affinity/tolerations so at least one node matches.
  4. If a PVC blocks scheduling, check PV/PVC availability zones and volume node affinity.

Example fix

// before: no node matches
// nodeSelector: {disktype: ssd} // no such nodes
// after
// nodeSelector: {disktype: nvme}
Defensive patterns

Strategy: validation

Validate before calling

nodes, _ := client.CoreV1().Nodes().List(ctx, metav1.ListOptions{}); for _, n := range nodes.Items { if nodeMatches(pod.Spec.NodeSelector, n.Labels) && taintsTolerated(pod.Spec.Tolerations, n.Spec.Taints) { return nil } }; return errors.New("no node satisfies selector/taints/resources")

Type guard

func schedulableSomewhere(nodes []v1.Node, pod v1.Pod) bool { for _, n := range nodes { if fits(n, pod) { return true } } return false }

Try / catch

code, err := getUntoleratedTaints(reason, msg); if code == proto.StatusCode_STATUSCHECK_UNKNOWN_UNSCHEDULABLE { log.Printf("scheduler said: %s: %s", reason, msg); return suggestFixFromMessage(msg) }

Prevention

When it happens

Trigger: getUntoleratedTaints runs taintsRe against the pod event message and finds zero matches; it returns fmt.Errorf("%s: %s", reason, message) with UNKNOWN_UNSCHEDULABLE instead of a specific taint code.

Common situations: Insufficient CPU/memory across all nodes; nodeSelector/affinity matching no nodes; pod's PVC not available on any node (volume topology); custom taints with unexpected wording not covered by Skaffold's regex.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/f2a3c3284efc8fe5. Report an issue: GitHub.