GoogleContainerTools/skaffold · error

failed to load manifest

Error message

failed to load manifest

What it means

RunPostHooks for the render phase loads the rendered manifest list with manifest.Load(list.Reader()) before applying post-render hooks. If loading/parsing the manifests fails, it returns a bare 'failed to load manifest' (note: unlike most errors here, the underlying cause is not wrapped).

Solutions

  1. Run the renderer alone (skaffold render) and inspect the output YAML for emptiness or syntax errors
  2. Check stdout pollution: earlier hooks or scripts must not print non-manifest data to stdout
  3. Validate the rendered YAML with 'kubectl apply --dry-run=client -f -' to find parse errors
  4. Fix the underlying renderer config (helm/kustomize) that produced invalid output

Example fix

// before: hook echoes noise to stdout, corrupting the manifest stream
postRender:
  hostHooks:
    - command: ["echo", "rendering done..."]
// after: send diagnostics to stderr
postRender:
  hostHooks:
    - command: ["/bin/sh", "-c", "echo rendering done... 1>&2"]
Defensive patterns

Strategy: validation

Validate before calling

data, err := io.ReadAll(list.Reader())
if err != nil { return err }
if len(bytes.TrimSpace(data)) == 0 {
    return errors.New("renderer produced empty manifest output")
}
if err := yaml.Unmarshal(data, &map[string]any{}); err != nil {
    return fmt.Errorf("manifests not valid YAML: %w", err)
}

Try / catch

updated, err := r.RunPostHooks(ctx, out, list)
if err != nil && err.Error() == "failed to load manifest" {
    // cause is unwrapped: dump the stream to debug
    log.Printf("dumping manifest stream for diagnosis:\n%s", rawOutput)
    return err
}

Prevention

When it happens

Trigger: Calling RunPostHooks with a reader (list.Reader()) whose content is empty, truncated, or not valid multi-document YAML/Kubernetes manifests — so manifest.Load cannot parse it.

Common situations: Renderer produced empty output (helm/kustomize failed silently or wrote nothing); manifests corrupted by a buggy previous post-render hook writing garbage to stdout; YAML syntax errors in the rendered output; binary or non-UTF8 data on the stream.

Related errors


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

Appendix: source

Thrown at pkg/skaffold/hooks/render.go:80

}

func (r renderRunner) GetConfigName() string {
	return r.configName
}

func (r renderRunner) RunPreHooks(ctx context.Context, out io.Writer) error {
	return r.run(ctx, out, r.PreHooks, phases.PreRender)
}

func (r renderRunner) RunPostHooks(ctx context.Context, list manifest.ManifestList, out io.Writer) (manifest.ManifestList, error) {
	logWriter := log.GetWriter()

	if len(r.PostHooks) > 0 {
		output.Default.Fprintln(logWriter, fmt.Sprintf("Starting %s hooks...", phases.PostRender))
	}
	updated, err := manifest.Load(list.Reader())
	if err != nil {
		return manifest.ManifestList{}, fmt.Errorf("failed to load manifest")
	}
	env := r.getEnv()
	for _, h := range r.PostHooks {
		if h.HostHook != nil {
			hook := hostHook{latest.HostHook{
				Command: h.HostHook.Command,
				OS:      h.HostHook.OS,
				Dir:     h.HostHook.Dir,
			}, env}
			var b bytes.Buffer
			if h.HostHook.WithChange {
				if err := hook.run(ctx, updated.Reader(), &b); err != nil {
					if errors.Is(err, &Skip{}) {
						continue
					}
					return manifest.ManifestList{}, err
				}
				if b.Len() == 0 {

View on GitHub (pinned to a1189de023)