googleapis/mcp-toolbox · error

destination_bucket cannot be empty for tool %q

Error message

destination_bucket cannot be empty for tool %q

What it means

Same pattern as source_bucket: destination_bucket is optional (*string) but must be non-empty when provided. Initialize rejects an explicitly empty destination bucket because the copy tool cannot resolve a target.

Source

Thrown at internal/tools/cloudstorage/cloudstoragecopyobject/cloudstoragecopyobject.go:80

	SourceBucket      *string                `yaml:"source_bucket,omitempty"`
	DestinationBucket *string                `yaml:"destination_bucket,omitempty"`
}

var _ tools.ToolConfig = Config{}

func (cfg Config) ToolConfigType() string {
	return resourceType
}

func (cfg Config) Initialize(context.Context) (tools.Tool, error) {
	if cfg.Description == "" {
		return nil, fmt.Errorf("description is required for tool %q", cfg.Name)
	}
	if cfg.SourceBucket != nil && *cfg.SourceBucket == "" {
		return nil, fmt.Errorf("source_bucket cannot be empty for tool %q", cfg.Name)
	}
	if cfg.DestinationBucket != nil && *cfg.DestinationBucket == "" {
		return nil, fmt.Errorf("destination_bucket cannot be empty for tool %q", cfg.Name)
	}

	sourceObjectParam := parameters.NewStringParameter(sourceObjectKey, "Full source object name (path) within the source bucket, e.g. 'path/to/file.txt'.")
	destinationObjectParam := parameters.NewStringParameter(destinationObjectKey, "Full destination object name (path) within the destination bucket, e.g. 'path/to/file.txt'.")
	allParameters := parameters.Parameters{}
	if cfg.SourceBucket == nil {
		allParameters = append(allParameters, parameters.NewStringParameter(sourceBucketKey, "Name of the Cloud Storage bucket containing the source object."))
	}
	allParameters = append(allParameters, sourceObjectParam)
	if cfg.DestinationBucket == nil {
		allParameters = append(allParameters, parameters.NewStringParameter(destinationBucketKey, "Name of the Cloud Storage bucket to copy into."))
	}
	allParameters = append(allParameters, destinationObjectParam)

	return Tool{
		BaseTool: tools.NewBaseTool(
			cfg,
			tools.GetAnnotationsOrDefault(cfg.Annotations, tools.NewDestructiveAnnotations),

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Provide a concrete destination bucket name or remove the key so it becomes an invocation-time parameter
  2. Fix the environment variable substitution that produced the empty string
  3. Validate rendered config files in CI before starting the server

Example fix

// before
  destinationBucket: ""
// after
  destinationBucket: my-dest-bucket
Defensive patterns

Strategy: validation

Validate before calling

func checkDestBucket(name string, ptr *string) error {
    if ptr != nil && *ptr == "" {
        return fmt.Errorf("tool %s: destination_bucket set but empty", name)
    }
    return nil
}

Type guard

func hasNonEmptyDestBucket(p *string) bool { return p == nil || *p != "" }

Try / catch

tool, err := cfg.Initialize(ctx)
if err != nil && strings.Contains(err.Error(), "destination_bucket cannot be empty") {
    return fmt.Errorf("provide a real destination bucket or omit the key: %w", err)
}

Prevention

When it happens

Trigger: `destinationBucket: ""` in tools.yaml, or an env/templated value that resolved to the empty string during config load.

Common situations: Copy-pasting the source_bucket block and forgetting to fill in the value; unset DEST_BUCKET env var; YAML key with no value.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/47831c8932543fcd. Report an issue: GitHub.