GoogleContainerTools/skaffold · error

unmarshaling config: %w

Error message

unmarshaling config: %w

What it means

After YAML→JSON conversion succeeds, Filter unmarshals each document into an unstructured.Unstructured object. UnmarshalJSON fails if the JSON is not a valid Kubernetes object (e.g. top-level JSON is not an object/mapping). The error is wrapped as 'unmarshaling config'.

Source

Thrown at pkg/skaffold/kubernetes/manifest/filter.go:40

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	k8syaml "sigs.k8s.io/yaml"
)

// Filter returns the manifest list that match any of the given `GroupKindSelector` items
func (l *ManifestList) Filter(selectors ...GroupKindSelector) (ManifestList, error) {
	if l == nil {
		return nil, nil
	}
	var filtered ManifestList
	for _, yByte := range *l {
		// Convert yaml byte config to unstructured.Unstructured
		jByte, err := k8syaml.YAMLToJSON(yByte)
		if err != nil {
			return nil, fmt.Errorf("yaml to json error: %w", err)
		}
		var obj unstructured.Unstructured
		if err := obj.UnmarshalJSON(jByte); err != nil {
			return nil, fmt.Errorf("unmarshaling config: %w", err)
		}
		gvk := obj.GroupVersionKind()
		for _, w := range selectors {
			if w.Matches(gvk.Group, gvk.Kind) {
				filtered.Append(yByte)
			}
		}
	}
	return filtered, nil
}

// SelectResources returns the resources defined in the manifest list that match any of the given `GroupKindSelector` items
func (l *ManifestList) SelectResources(selectors ...GroupKindSelector) ([]unstructured.Unstructured, error) {
	if l == nil {
		return nil, nil
	}
	var customResources []unstructured.Unstructured
	for _, yByte := range *l {

View on GitHub (pinned to a1189de023)

Solutions

  1. Ensure every YAML document is a mapping (starts with 'apiVersion:'/'kind:'), not a bare list or scalar
  2. Split list-style YAML (kind: List) into separate documents or use the List kind properly
  3. Remove empty documents / stray '---' separators that yield empty JSON
  4. Check upstream render output for concatenated non-manifest content

Example fix

// before: file is a YAML list of resources
- apiVersion: v1
  kind: Service
- apiVersion: v1
  kind: Deployment
// after: use a List document or one object per file
apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: Service
- apiVersion: v1
  kind: Deployment
Defensive patterns

Strategy: validation

Validate before calling

func isMappingDoc(doc []byte) bool {
  var v interface{}
  if err := yaml.Unmarshal(doc, &v); err != nil { return false }
  _, ok := v.(map[string]interface{})
  return ok
}
// reject documents where !isMappingDoc(m) before calling Filter

Type guard

func isK8sObject(m map[string]interface{}) bool {
  _, hasKind := m["kind"]
  _, hasAPIVersion := m["apiVersion"]
  return hasKind && hasAPIVersion
}

Try / catch

if _, err := manifests.Selectors(sel).Filter(...); err != nil {
  if strings.Contains(err.Error(), "unmarshaling config") {
    // dump the offending document for inspection and fail fast
    return fmt.Errorf("non-object manifest document: %w", err)
  }
  return err
}

Prevention

When it happens

Trigger: Calling ManifestList.Filter where a manifest converts to JSON that is not an object — e.g. the YAML document is a scalar or list, or the YAMLToJSON output is structurally invalid for unstructured decoding.

Common situations: A YAML file that is just a list of resources instead of individual documents, a manifest starting with '---' producing an empty document, or pipeline steps that append non-manifest text to the manifest stream.

Related errors


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