goharbor/harbor · error

the resource cannot be null

Error message

the resource cannot be null

What it means

Returned by the Quay adapter's PrepareForPush (src/pkg/reg/adapter/quay/adapter.go:155), which pre-creates namespaces when autoCreateNs is enabled. It rejects a nil *model.Resource element in the slice before touching resource.Metadata, because the next line dereferences it.

Source

Thrown at src/pkg/reg/adapter/quay/adapter.go:155

			},
		},
		SupportedTriggers: []string{
			model.TriggerTypeManual,
			model.TriggerTypeScheduled,
		},
	}, nil
}

// PrepareForPush does the prepare work that needed for pushing/uploading the resource
// eg: create the namespace or repository
func (a *adapter) PrepareForPush(resources []*model.Resource) error {
	if !a.autoCreateNs {
		return nil
	}
	namespaces := []string{}
	for _, resource := range resources {
		if resource == nil {
			return errors.New("the resource cannot be null")
		}
		if resource.Metadata == nil {
			return errors.New("the metadata of resource cannot be null")
		}
		if resource.Metadata.Repository == nil {
			return errors.New("the namespace of resource cannot be null")
		}
		if len(resource.Metadata.Repository.Name) == 0 {
			return errors.New("the name of the namespace cannot be null")
		}
		paths := strings.Split(resource.Metadata.Repository.Name, "/")
		namespace := paths[0]
		namespaces = append(namespaces, namespace)
	}

	for _, namespace := range namespaces {
		err := a.createNamespace(&model.Namespace{
			Name: namespace,

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Fix the slice construction: never append nil; abort or skip-and-log the whole element on fetch error.
  2. Pre-validate resources (see validationCode) to identify the index of the nil entry.
  3. Note the guard only runs when autoCreateNs is true — if you do not need namespace auto-creation, configure the Quay endpoint without it, but the nil entry is still a caller bug worth fixing.
  4. Add a unit test asserting no nil elements in the pipeline output.

Example fix

// before
var resources []*model.Resource
for _, art := range arts {
    if art == nil {
        resources = append(resources, nil)
    }
}

// after
var resources []*model.Resource
for _, art := range arts {
    if art == nil {
        continue // or return an error
    }
    resources = append(resources, art)
}
Defensive patterns

Strategy: validation

Validate before calling

for i, r := range resources {
	if r == nil {
		return fmt.Errorf("resources[%d] is nil", i)
	}
}
// optional: skip guard entirely by configuring the Quay endpoint without auto namespace creation

Type guard

func nonNilResources(rs []*model.Resource) bool {
	for _, r := range rs {
		if r == nil {
			return false
		}
	}
	return true
}

Try / catch

if err := a.PrepareForPush(resources); err != nil {
	if strings.Contains(err.Error(), "the resource cannot be null") {
		// nil element in slice: fix construction, filter nils
	}
	return err
}

Prevention

When it happens

Trigger: Calling quay PrepareForPush with a slice containing a nil entry while the adapter was created with auto-namespace-creation enabled (registry endpoint configured for auto creating namespaces).

Common situations: Custom replication pipelines appending nil placeholders on fetch failure; slices built by appending conditional results; refactoring that introduces sparse resources.

Related errors


AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16). Data as JSON: /api/errors/c284c88815a06f86. Report an issue: GitHub.