argoproj/argo-workflows · error

failed to parse YAML from file

Error message

failed to parse YAML from file %s: %w

What it means

When building the in-memory template store for the offline client, argo walks the given paths and parses every YAML/JSON manifest. If any document fails to parse into a Kubernetes object, the walk is aborted and this wrapped error (with the offending file path) is returned from newOfflineClient.

Solutions

  1. Open the file named in the message and fix the YAML syntax error reported by the wrapped parse error.
  2. Run `yamllint` or a YAML parser on the file to pinpoint the broken document.
  3. Split multi-document files and validate each document individually to find the failing one.

Example fix

// before (broken YAML)
metadata:
  name: tmpl
 spec:
   templates: []
// after
metadata:
  name: tmpl
spec:
  templates: []
Defensive patterns

Strategy: validation

Validate before calling

import "sigs.k8s.io/yaml"
func validateYAMLFile(path string) error {
    b, err := os.ReadFile(path)
    if err != nil { return err }
    var out []map[string]any
    return yaml.Unmarshal(b, &out)
}

Try / catch

client, err := apiclient.NewOfflineClient(ctx, paths)
if err != nil {
    var pathErr *fs.PathError
    if strings.Contains(err.Error(), "failed to parse YAML from file") {
        // surface err to the user: fix the YAML in the named file
    }
    return err
}

Prevention

When it happens

Trigger: Running `argo lint` / creating an offline client over a path containing a file whose YAML is malformed, has bad indentation, or contains a document that common.ParseObjects cannot parse into a k8s object (pr.Err non-nil).

Common situations: Hand-edited manifest with a YAML typo; a file with mixed tabs/spaces; multi-doc file where one document is broken; passing a directory that includes generated or partial files that are not valid manifests.

Understand the failure class

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/205056844ec58a6b. Report an issue: GitHub.

Appendix: source

Thrown at pkg/apiclient/offline-client.go:55

}

var ErrOffline = fmt.Errorf("not supported when you are in offline mode")

var _ Client = &offlineClient{}

// newOfflineClient creates a client that keeps all files (or files recursively contained within a path) given to it in memory.
// It is useful for linting a set of files without having to connect to a cluster.
func newOfflineClient(ctx context.Context, paths []string) (context.Context, Client, error) {
	clusterWorkflowTemplateGetter := &offlineClusterWorkflowTemplateGetter{
		clusterWorkflowTemplates: map[string]*wfv1.ClusterWorkflowTemplate{},
	}
	workflowTemplateGetters := offlineWorkflowTemplateGetterMap{}
	for _, basePath := range paths {
		err := file.WalkManifests(ctx, basePath, func(path string, bytes []byte) error {
			for _, pr := range common.ParseObjects(ctx, bytes, false) {
				obj, err := pr.Object, pr.Err
				if err != nil {
					return fmt.Errorf("failed to parse YAML from file %s: %w", path, err)
				}

				if obj == nil {
					continue // could not parse to kubernetes object
				}

				objName := obj.GetName()
				namespace := obj.GetNamespace()

				switch v := obj.(type) {
				case *wfv1.ClusterWorkflowTemplate:
					if _, ok := clusterWorkflowTemplateGetter.clusterWorkflowTemplates[objName]; ok {
						return fmt.Errorf("duplicate ClusterWorkflowTemplate found: %q", objName)
					}
					clusterWorkflowTemplateGetter.clusterWorkflowTemplates[objName] = v

				case *wfv1.WorkflowTemplate:
					getter, ok := workflowTemplateGetters[namespace]

View on GitHub (pinned to 35bff19146)