goharbor/harbor · error

the metadata of resource cannot be null

Error message

the metadata of resource cannot be null

What it means

Returned by the Quay adapter's PrepareForPush (src/pkg/reg/adapter/quay/adapter.go:158) when a resource is non-nil but resource.Metadata is nil. With autoCreateNs enabled the adapter must read Metadata.Repository.Name to derive the Quay namespace to create, so a missing Metadata struct aborts the operation.

Source

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

			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,
		})
		if err != nil {
			return fmt.Errorf("create namespace '%s' in Quay error: %v", namespace, err)

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Populate Metadata (with Repository.Name) for every resource that will be pushed.
  2. Run the pre-flight validation helper to catch the failing index early.
  3. Grep construction sites for 'model.Resource{' and require Metadata on push paths.
  4. Share one resource-builder function between production and tests.

Example fix

// before
res := &model.Resource{Type: model.ResourceTypeImage}

// after
res := &model.Resource{
    Type:     model.ResourceTypeImage,
    Metadata: &model.ResourceMetadata{
        Repository: &model.Repository{Name: "myteam/ubuntu"},
    },
}
Defensive patterns

Strategy: validation

Validate before calling

for i, r := range resources {
	if r == nil || r.Metadata == nil {
		return fmt.Errorf("resources[%d]: missing resource or metadata", i)
	}
}

Type guard

func hasMetadata(r *model.Resource) bool { return r != nil && r.Metadata != nil }

Try / catch

if err := a.PrepareForPush(resources); err != nil {
	if strings.Contains(err.Error(), "metadata of resource cannot be null") {
		// populate Metadata and retry
	}
	return err
}

Prevention

When it happens

Trigger: Calling quay PrepareForPush with auto-create enabled on a resource built without the Metadata field, e.g. &model.Resource{Type: ...} only.

Common situations: Reusing deletion-style or listing-style resource objects (which omit Metadata) on the push path; hand-built test fixtures; partial struct clones.

Related errors


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