GoogleContainerTools/skaffold · error

custom action %s have more than one execution mode defined.

Error message

custom action %s have more than one execution mode defined. custom actions must have only one execution mode

What it means

A Skaffold custom action must specify exactly one execution mode: either Kubernetes cluster execution or local execution, not both. validateCustomActionsExecModes rejects actions where both `ExecutionModeConfig.KubernetesClusterExecutionMode` and `LocalExecutionMode` are set.

Source

Thrown at pkg/skaffold/schema/validation/validation.go:787

	for _, a := range acs {
		if len(a.Containers) == 0 {
			errs = append(errs, fmt.Errorf("custom action %s doesn't have containers. custom actions must have one or more containers associated", a.Name))
		}
	}
	return
}

func validateCustomActionsExecModes(runCtx *runcontext.RunContext) (errs []error) {
	acs := []latest.Action{}

	for _, pipeline := range runCtx.GetPipelines() {
		acs = append(acs, pipeline.CustomActions...)
	}

	for _, a := range acs {
		if a.ExecutionModeConfig.KubernetesClusterExecutionMode != nil && a.ExecutionModeConfig.LocalExecutionMode != nil {
			errs = append(errs, fmt.Errorf("custom action %s have more than one execution mode defined. custom actions must have only one execution mode", a.Name))
		}
	}

	return
}

// validateCustomTest
// - makes sure that command is not empty
// - makes sure that dependencies.ignore is only used in conjunction with dependencies.paths
func validateCustomTest(cfg *parser.SkaffoldConfigEntry, tcs []*latest.TestCase) (cfgErrs []ErrorWithLocation) {
	for i, tc := range tcs {
		for j, ct := range tc.CustomTests {
			if ct.Command == "" {
				cfgErrs = append(cfgErrs, ErrorWithLocation{
					Error:    fmt.Errorf("custom test command must not be empty;"),
					Location: cfg.YAMLInfos.Locate(&cfg.Test[i].CustomTests[j]),
				})
				return

View on GitHub (pinned to a1189de023)

Solutions

  1. Remove one of the two execution mode blocks so only kubernetesCluster or local remains
  2. Decide the intended execution target for the action and keep only that block
  3. Re-run the skaffold command to confirm validation passes

Example fix

# before
customActions:
- name: db-migrate
  executionMode:
    kubernetesCluster: {}
    local: {}
# after
customActions:
- name: db-migrate
  executionMode:
    kubernetesCluster: {}
Defensive patterns

Strategy: validation

Validate before calling

func singleExecMode(action CustomAction) error {
	set := 0
	if action.ExecutionMode.KubernetesCluster != nil { set++ }
	if action.ExecutionMode.Local != nil { set++ }
	if set > 1 {
		return fmt.Errorf("custom action %q sets both cluster and local execution modes", action.Name)
	}
	return nil
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Processing a skaffold.yaml where a customAction's executionMode config sets both the kubernetesCluster sub-config and the local sub-config simultaneously.

Common situations: Copy-pasting executionMode blocks between actions and keeping both variants; merging config files that each set a different execution mode; experimenting with local runs then switching to cluster runs without deleting the old block.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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