GoogleContainerTools/skaffold · error

post-sync hooks failed for artifact %q: %w

Error message

post-sync hooks failed for artifact %q: %w

What it means

PodSyncer.Sync runs post-sync lifecycle hooks after the file copy/delete completes. If RunPostHooks fails, Skaffold wraps the error with the artifact image name. Note the copy/delete already succeeded at this point — the synced state is in place but the hook (e.g. a restart or reload trigger) failed.

Source

Thrown at pkg/skaffold/sync/sync.go:301

		copy = append(copy, k)
	}
	for k := range item.Delete {
		delete = append(delete, k)
	}

	opts, err := hooks.NewSyncEnvOpts(item.Artifact, item.Image, copy, delete, *s.namespaces, s.kubectl.KubeContext)
	if err != nil {
		return err
	}
	hooksRunner := hooks.NewSyncRunner(s.kubectl, item.Artifact.ImageName, item.Image, *s.namespaces, s.formatter, item.Artifact.Sync.LifecycleHooks, opts)
	if err := hooksRunner.RunPreHooks(ctx, out); err != nil {
		return fmt.Errorf("pre-sync hooks failed for artifact %q: %w", item.Artifact.ImageName, err)
	}
	if err := s.sync(ctx, item); err != nil {
		return err
	}
	if err := hooksRunner.RunPostHooks(ctx, out); err != nil {
		return fmt.Errorf("post-sync hooks failed for artifact %q: %w", item.Artifact.ImageName, err)
	}
	return nil
}

func (s *PodSyncer) sync(ctx context.Context, item *Item) error {
	if len(item.Copy) > 0 {
		log.Entry(ctx).Info("Copying files:", item.Copy, "to", item.Image)

		if err := Perform(ctx, item.Image, item.Copy, s.copyFileFn, *s.namespaces, s.kubectl.KubeContext); err != nil {
			return fmt.Errorf("copying files: %w", err)
		}
	}

	if len(item.Delete) > 0 {
		log.Entry(ctx).Info("Deleting files:", item.Delete, "from", item.Image)

		if err := Perform(ctx, item.Image, item.Delete, s.deleteFileFn, *s.namespaces, s.kubectl.KubeContext); err != nil {
			return fmt.Errorf("deleting files: %w", err)

View on GitHub (pinned to a1189de023)

Solutions

  1. Re-run the postSync command manually via kubectl exec to see the real failure output
  2. Fix the postSync spec (containerName, command) in skaffold.yaml for the named artifact
  3. If the hook depends on the synced files, validate the changed files locally (build/test) before saving them

Example fix

// before
postSync:
  - container: {containerName: sidecar-not-there, command: ["kill", "-HUP", "1"]}
// after
postSync:
  - container: {containerName: app, command: ["kill", "-HUP", "1"]}
Defensive patterns

Strategy: try-catch

Validate before calling

for _, h := range a.Sync.LifecycleHooks.PostSync {
    if h.Container != nil && h.Container.ContainerName == "" { return errors.New("postSync container hook missing containerName") }
    if h.Exec != nil && len(h.Exec.Command) == 0 { return errors.New("empty postSync exec command") }
}

Try / catch

err := s.Sync(ctx, out, names, item)
if err != nil {
    if strings.Contains(err.Error(), "post-sync hooks failed") {
        log.Warnf("files synced but postSync hook failed (state is updated): %v", err)
        // treat as non-fatal if the hook is only a reload trigger
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Any `sync.lifecycleHooks.postSync` exec/container hook fails during a file-change sync: non-zero exit, kubectl exec/connect error, missing target container, or timeout.

Common situations: postSync container restart hook naming a container that doesn't exist in the pod; network/CNI issue making kubectl exec fail intermittently; hook command failing because the just-synced file is invalid (compile error picked up by reload command).

Related errors


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