goharbor/harbor · error

[tencent-tcr.PrepareForPush] the metadata of resource cannot

Error message

[tencent-tcr.PrepareForPush] the metadata of resource cannot be null

What it means

Returned by the Tencent TCR adapter's PrepareForPush (src/pkg/reg/adapter/tencentcr/adapter.go:218) when a resource is non-nil but resource.Metadata is nil. The adapter must read Metadata.Repository.Name to derive both the TCR namespace (paths[0]) and repository (path.Join(paths[1:]...)) it will create via the Tencent API.

Source

Thrown at src/pkg/reg/adapter/tencentcr/adapter.go:218

				Style: model.FilterStyleTypeText,
			},
		},
		SupportedTriggers: []string{
			model.TriggerTypeManual,
			model.TriggerTypeScheduled,
		},
	}
	return
}

func (a *adapter) PrepareForPush(resources []*model.Resource) (err error) {
	log.Debugf("[tencent-tcr.PrepareForPush]")
	for _, resource := range resources {
		if resource == nil {
			return errors.New("the resource cannot be null")
		}
		if resource.Metadata == nil {
			return errors.New("[tencent-tcr.PrepareForPush] the metadata of resource cannot be null")
		}
		if resource.Metadata.Repository == nil {
			return errors.New("[tencent-tcr.PrepareForPush] the namespace of resource cannot be null")
		}
		if len(resource.Metadata.Repository.Name) == 0 {
			return errors.New("[tencent-tcr.PrepareForPush] the name of the namespace cannot be null")
		}
		var paths = strings.Split(resource.Metadata.Repository.Name, "/")
		var namespace = paths[0]
		var repository = path.Join(paths[1:]...)

		log.Debugf("[tencent-tcr.PrepareForPush.createPrivateNamespace] namespace=%s", namespace)
		err = a.createPrivateNamespace(namespace)
		if err != nil {
			return
		}
		log.Debugf("[tencent-tcr.PrepareForPush.createRepository] namespace=%s, repository=%s", namespace, repository)
		err = a.createRepository(namespace, repository)

View on GitHub (pinned to 7b2fd08cc5)

Solutions

  1. Populate resource.Metadata together with Metadata.Repository before calling PrepareForPush.
  2. Use the pre-flight validation helper for an indexed, adapter-agnostic error message.
  3. Grep 'model.Resource{' literals on push paths and require Metadata.
  4. Centralize resource construction in one tested builder.

Example fix

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

// after
res := &model.Resource{
    Type:     model.ResourceTypeImage,
    Metadata: &model.ResourceMetadata{
        Repository: &model.Repository{Name: "myns/myrepo"},
    },
}
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 (with Repository.Name) and retry
	}
	return err
}

Prevention

When it happens

Trigger: Passing a resource constructed without Metadata to tencentcr PrepareForPush, e.g. a resource built only with Type or Deleted flags.

Common situations: Reusing deletion/listing-shaped resource objects on the push path; hand-built literals; partial clones during refactors; fixture drift between adapters' tests.

Related errors


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