Skip to content

bug: project run --init-resources/--extra-resources reject manifests with a leading comment document #207

Description

@ytsarev

What happened?

crossplane project run --init-resources <file> (and --extra-resources) fails with:

encountered an invalid or empty raw resource

whenever the manifest begins with a comment block before the first --- document separator — i.e. a file-level header comment, which is a very common convention. kubectl apply -f on the exact same file works, because it skips empty/null documents. So a manifest that is perfectly valid everywhere else in the ecosystem is rejected by project run.

How can we reproduce it?

cat > prereq.yaml <<'EOF'
# A header comment describing this file.
# It spans a few lines before the first resource.
---
apiVersion: v1
kind: Namespace
metadata:
  name: demo
EOF

# Fails:
crossplane project run --init-resources prereq.yaml
#   Error: encountered an invalid or empty raw resource

# The identical file applies fine with kubectl:
kubectl apply --dry-run=client -f prereq.yaml

Deleting the leading comment lines (so the file starts at the first resource), or moving the comment to after the first ---, makes the error go away. The same applies to --extra-resources.

Root cause

The YAML stream loader splits on --- and drops only byte-empty chunks, but a comment-only chunk is non-empty text, so it survives, unmarshals to an empty RawExtension, and ApplyResources then treats that empty resource as fatal:

  1. cmd/crossplane/render/load.goLoadYAMLStreamFromFile reads documents with k8s.io/apimachinery/pkg/util/yaml.NewYAMLReader and skips only chunks where len(bytes) == 0. The leading # ... block (before the first ---) is non-empty bytes, so it is returned as a document.

  2. cmd/crossplane/project/run.go — each document is sigs.k8s.io/yaml.Unmarshal'd into a runtime.RawExtension. A comment-only document is valid YAML that unmarshals to null, leaving RawExtension.Raw empty (no error at this step).

  3. internal/project/install.goApplyResources hard-fails on it:

    for _, raw := range resources {
        if len(raw.Raw) == 0 {
            return errors.New("encountered an invalid or empty raw resource")
        }
        ...

Suggested fix

Skip empty raw resources instead of erroring, matching how kubectl and the rest of the ecosystem treat empty/null documents. In ApplyResources:

if len(raw.Raw) == 0 {
    continue
}

That single spot covers both --init-resources and --extra-resources. Happy to open a PR with this plus a regression test if the approach looks right.

What environment did it happen in?

  • Crossplane CLI version: v2.4.0 (also present on current main, 5342ad7 / v2.5.0-rc.0 — the ApplyResources code is unchanged)
  • Platform: reproduced on darwin/arm64 and linux/amd64 (the logic is platform-independent)
  • Crossplane version: n/a (fails client-side before contacting a control plane)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions