{"record":{"id":"5a10818bfd3369e0","repo":"GoogleContainerTools/skaffold","slug":"found-existing-node-affinity-for-os-arch-s","errorCode":null,"errorMessage":"found existing node affinity for os/arch: %s","messagePattern":"found existing node affinity for os/arch: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/kubernetes/manifest/affinity.go","lineNumber":219,"sourceCode":"\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err = json.Unmarshal(data, &affinity); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif affinity.NodeAffinity == nil {\n\t\taffinity.NodeAffinity = &v1.NodeAffinity{}\n\t}\n\tif affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution == nil {\n\t\taffinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution = &v1.NodeSelector{}\n\t}\n\n\tfor _, term := range affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms {\n\t\tfor _, exp := range term.MatchExpressions {\n\t\t\tif exp.Key == nodeOperatingSystemLabel || exp.Key == nodeArchitectureLabel {\n\t\t\t\treturn nil, fmt.Errorf(\"found existing node affinity for os/arch: %s\", exp)\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms) == 0 {\n\t\taffinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms = append(affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms, v1.NodeSelectorTerm{})\n\t}\n\n\tvar terms []v1.NodeSelectorTerm\n\tfor _, pl := range platforms {\n\t\tfor _, term := range affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms {\n\t\t\tt := term.DeepCopy()\n\t\t\tif pl.OS != \"\" {\n\t\t\t\tt.MatchExpressions = append(t.MatchExpressions, v1.NodeSelectorRequirement{\n\t\t\t\t\tKey:      nodeOperatingSystemLabel,\n\t\t\t\t\tOperator: v1.NodeSelectorOpIn,\n\t\t\t\t\tValues:   []string{pl.OS},\n\t\t\t\t})","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/kubernetes/manifest/affinity.go#L201-L237","documentation":"Skaffold's updateAffinity scans a workload's pod-template node affinity for pre-existing match expressions on the kubernetes.io/os or kubernetes.io/arch node labels. If any already exist, it refuses to add its own os/arch affinity to avoid conflicting or duplicate selector terms, and returns this error. It is a deliberate guard: only one os/arch affinity management owner is supported.","triggerScenarios":"Calling ManifestList.Visit (via the affinity transformer) on a manifest whose pod spec affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution already contains a MatchExpressions entry with Key 'kubernetes.io/os' or 'kubernetes.io/arch'.","commonSituations":"Deploying a manifest that was previously processed by skaffold's affinity patching (output fed back in), hand-written manifests that pin os/arch node affinity, or Helm/kustomize outputs embedding such selectors.","solutions":["Remove the existing nodeSelectorTerms match expressions on kubernetes.io/os or kubernetes.io/arch from the manifest's pod affinity before running skaffold","Use nodeSelector or a differently-keyed affinity term if you need custom scheduling and let skaffold own the os/arch affinity","Disable skaffold's affinity transformation in your render/deploy configuration so it does not try to patch affinity"],"exampleFix":"// before\naffinity:\n  nodeAffinity:\n    requiredDuringSchedulingIgnoredDuringExecution:\n      nodeSelectorTerms:\n      - matchExpressions:\n        - key: kubernetes.io/arch\n          operator: In\n          values: [amd64]\n// after (let skaffold add it)\naffinity:\n  nodeAffinity:\n    requiredDuringSchedulingIgnoredDuringExecution:\n      nodeSelectorTerms:\n      - matchExpressions:\n        - key: some-other-label\n          operator: In\n          values: [foo]","handlingStrategy":"validation","validationCode":"func hasOSArchAffinity(podSpec map[string]interface{}) bool {\n  aff, ok := podSpec[\"affinity\"].(map[string]interface{}); if !ok { return false }\n  na, ok := aff[\"nodeAffinity\"].(map[string]interface{}); if !ok { return false }\n  req, ok := na[\"requiredDuringSchedulingIgnoredDuringExecution\"].(map[string]interface{}); if !ok { return false }\n  terms, _ := req[\"nodeSelectorTerms\"].([]interface{})\n  for _, t := range terms {\n    tm, _ := t.(map[string]interface{})\n    exprs, _ := tm[\"matchExpressions\"].([]interface{})\n    for _, e := range exprs {\n      em, _ := e.(map[string]interface{})\n      if k, _ := em[\"key\"].(string); k == \"kubernetes.io/os\" || k == \"kubernetes.io/arch\" { return true }\n    }\n  }\n  return false\n}\n// skip skaffold affinity patching if hasOSArchAffinity(podSpec) is true","typeGuard":"isOSArchKey := func(exp map[string]interface{}) bool {\n  k, _ := exp[\"key\"].(string)\n  return k == \"kubernetes.io/os\" || k == \"kubernetes.io/arch\"\n}","tryCatchPattern":null,"preventionTips":["Do not pre-seed os/arch node affinity in source manifests you feed to skaffold","Keep skaffold-transformed output out of the input path (no feeding rendered output back through render again)","Use a different label key for custom scheduling constraints","Review rendered output with 'skaffold render' once to learn which manifests skaffold mutates"],"tags":["kubernetes","affinity","manifest"],"backgroundTag":"conflicting-node-affinity","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}