GoogleContainerTools/skaffold · error

sync failed for artifact %q

Error message

sync failed for artifact %q

What it means

Aggregated failure reported by the syncer mux when at least one, and possibly all, of the registered syncers failed to sync the artifact. Each syncer's error is collected and wrapped under this message; per the code comment, an error is returned only when all syncers fail, so seeing it means no syncer succeeded for the artifact.

Source

Thrown at pkg/skaffold/sync/syncer_mux.go:40

	"io"

	"github.com/pkg/errors"

	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/output/log"
)

type SyncerMux []Syncer

func (s SyncerMux) Sync(ctx context.Context, out io.Writer, item *Item) error {
	var errs []error
	for _, syncer := range s {
		if err := syncer.Sync(ctx, out, item); err != nil {
			errs = append(errs, err)
		}
	}

	if len(errs) > 0 {
		err := fmt.Errorf("sync failed for artifact %q", item.Image)

		for _, e := range errs {
			err = errors.Wrap(err, e.Error())
		}

		// Return an error only if all syncers fail
		if len(errs) == len(s) {
			return err
		}

		// Otherwise log the error as a warning
		log.Entry(ctx).Warn(err.Error())
	}

	return nil
}

View on GitHub (pinned to a1189de023)

Solutions

  1. Read the wrapped per-syncer errors to see why each syncer failed
  2. Confirm the artifact was deployed and its image tag matches (`kubectl get pods -o jsonpath='{.items[*].spec.containers[*].image}'`)
  3. Ensure pods are Running and restart sync after redeploy
  4. Check container filesystem permissions/paths in the sync rule (dest)

Example fix

// before: pod not yet running when sync fires
skaffold dev  # sync fails for artifact my/image
// after: wait for deploy, or redeploy
kubectl rollout status deploy/myapp && skaffold dev
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm image is deployed before sync
pods, _ := kubeClient.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{FieldSelector: "status.phase=Running"})
found := false
for _, p := range pods.Items {
    for _, c := range p.Spec.Containers {
        if c.Image == item.Image { found = true }
    }
}
if !found { return fmt.Errorf("image %q not deployed; skip sync", item.Image) }

Type guard

func imageDeployed(pods *corev1.PodList, image string) bool {
    for _, p := range pods.Items {
        for _, c := range p.Spec.Containers {
            if c.Image == image { return true }
        }
    }
    return false
}

Try / catch

if err := mux.Sync(ctx, out, item); err != nil {
    if strings.HasPrefix(err.Error(), "sync failed for artifact") {
        log.Warnf("all syncers failed for %s: %v", item.Image, err)
        return // or fall back to full rebuild+redeploy
    }
}

Prevention

When it happens

Trigger: `mux.Sync` iterates its syncers, any returning errors are appended; when `len(errs) > 0` it builds `fmt.Errorf("sync failed for artifact %q", item.Image)` and wraps every collected error. Triggered when e.g. container sync and pod-based sync both fail for `item.Image`.

Common situations: No running pod matches the image (not deployed yet); kubectl exec fails on all pods; file permissions prevent copying into the container; image name mismatch between built artifact and deployed pod.

Related errors


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