GoogleContainerTools/skaffold · error

getting render output path: %w

Error message

getting render output path: %w

What it means

Before creating the renderer, `NewForConfig` resolves the hydration directory (where rendered k8s manifests are written, default `.kpt-pipeline`) via `util.GetHydrationDir`. This wraps failures to compute or create that directory — filesystem path errors or mkdir permission failures.

Source

Thrown at pkg/skaffold/runner/new.go:79

	sourceDependencies := graph.NewSourceDependenciesCache(runCtx, store, g)

	isLocalImage := func(imageName string) (bool, error) {
		return isImageLocal(runCtx, imageName)
	}

	// Always add skaffold-specific labels, except during `skaffold render`
	labeller := label.NewLabeller(runCtx.AddSkaffoldLabels(), runCtx.CustomLabels(), runCtx.GetRunID())
	tester, err := getTester(ctx, runCtx, isLocalImage)
	if err != nil {
		endTrace(instrumentation.TraceEndError(err))
		return nil, fmt.Errorf("creating tester: %w", err)
	}

	var deployer deploy.Deployer

	hydrationDir, err := util.GetHydrationDir(runCtx.Opts, runCtx.WorkingDir, true, isKptRendererOrDeployerUsed(runCtx.Pipelines))
	if err != nil {
		return nil, fmt.Errorf("getting render output path: %w", err)
	}

	renderer, err := GetRenderer(ctx, runCtx, hydrationDir, labeller.Labels(), runCtx.UsingLegacyHelmDeploy())
	if err != nil {
		endTrace(instrumentation.TraceEndError(err))
		return nil, fmt.Errorf("creating renderer: %w", err)
	}

	deployer, err = GetDeployer(ctx, runCtx, labeller, hydrationDir, runCtx.UsingLegacyHelmDeploy())
	if err != nil {
		endTrace(instrumentation.TraceEndError(err))
		return nil, fmt.Errorf("creating deployer: %w", err)
	}
	rOpts := platform.ResolverOpts{
		KubeContext:               runCtx.KubeContext,
		CliPlatformsSelection:     runCtx.Opts.Platforms,
		CheckClusterNodePlatforms: runCtx.CheckClusterNodePlatforms(),
		DisableMultiPlatformBuild: runCtx.DisableMultiPlatformBuild(),

View on GitHub (pinned to a1189de023)

Solutions

  1. Ensure the `--hydration-dir` path's parent is writable (`ls -ld`, check permissions).
  2. Confirm the hydration dir path is not an existing regular file; remove or rename it.
  3. If not using kpt, no hydration dir is needed — check why a kpt renderer/deployer was selected (skaffold.yaml renderer/deployer config).
  4. In CI, use `--assume-yes=true` to skip the interactive non-empty-dir prompt that can otherwise hang or exit.

Example fix

// CI command before
skaffold render --hydration-dir /ro-mount/.kpt-pipeline
// after
skaffold render --hydration-dir /tmp/.kpt-pipeline --assume-yes=true
Defensive patterns

Strategy: validation

Validate before calling

func hydrationDirReady(dir string) error {
  st, err := os.Stat(dir)
  if err == nil && !st.IsDir() {
    return fmt.Errorf("%s exists and is not a directory", dir)
  }
  return os.MkdirAll(dir, 0o755)
}

Try / catch

runner, err := runner.NewForConfig(runCtx)
if err != nil {
  if strings.Contains(err.Error(), "getting render output path") {
    return fmt.Errorf("hydration dir unusable (permissions? file conflict?): %w", err)
  }
  return err
}

Prevention

When it happens

Trigger: Using a kpt renderer/deployer while `filepath.Abs(opts.HydrationDir)` fails, or `os.MkdirAll(hydrationDir)` fails because the parent directory is read-only, the path exists as a file, or the disk is full.

Common situations: Running `skaffold dev`/`render` with `--hydration-dir` inside a read-only mount; `--hydration-dir` colliding with an existing regular file; restricted CI container filesystems.

Related errors


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