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).

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)

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.