GoogleContainerTools/skaffold · error

bucket name is empty

Error message

bucket name is empty

What it means

parseGCSURI parses a gs:// URI into bucket and object components. After url.Parse, it requires the scheme to be 'gs' and the URI host component (the bucket) to be non-empty; an empty host means no bucket name was supplied, so it throws 'bucket name is empty'.

Source

Thrown at pkg/skaffold/gcs/client/native.go:142

		if err != nil {
			return err
		}
	}

	return bucket.UploadObject(ctx, dstObj, f)
}

func (n *Native) parseGCSURI(uri string) (uriInfo, error) {
	var gcsobj uriInfo
	u, err := url.Parse(uri)
	if err != nil {
		return uriInfo{}, fmt.Errorf("cannot parse URI %q: %w", uri, err)
	}
	if u.Scheme != "gs" {
		return uriInfo{}, fmt.Errorf("URI scheme is %q, must be 'gs'", u.Scheme)
	}
	if u.Host == "" {
		return uriInfo{}, errors.New("bucket name is empty")
	}
	gcsobj.Bucket = u.Host
	// If we do this with the url package it will scape the `?` character, breaking the glob.
	gcsobj.ObjPath = strings.TrimLeft(strings.ReplaceAll(uri, "gs://"+u.Host, ""), "/")

	return gcsobj, nil
}

func (n *Native) filesToDownload(ctx context.Context, bucket bucketHandler, urinfo uriInfo) (map[string]string, error) {
	uriToLocalPath := map[string]string{}

	// The exact match is with the original glob expression. This could be:
	// 1. a/b/c -> It will return the file `c` under a/b/ if it exists
	// 2. a/b/c* -> It will return any file under a/b/ that starts with c, e.g, c1, c-other, etc
	// 3. a/b/c** -> It will return any file that starts with 'c', and files inside any folder starting with 'c'. It is doing the recursion already
	exactMatches, err := bucket.ListObjects(ctx, &storage.Query{MatchGlob: urinfo.ObjPath})
	if err != nil {
		return nil, err

View on GitHub (pinned to a1189de023)

Solutions

  1. Check the configured GCS URI and add the bucket name: 'gs://my-bucket/path'
  2. Verify the env/config variable holding the bucket name is non-empty before building the URI
  3. If using a path-style value like 'gs://bucket/obj', confirm no leading slash swallowed the bucket ('gs:///obj' is invalid)

Example fix

// before
uri := fmt.Sprintf("gs://%s/%s", os.Getenv("BUCKET"), object) // BUCKET empty -> gs:///obj
// after
bucket := os.Getenv("BUCKET")
if bucket == "" { log.Fatal("BUCKET env var must be set") }
uri := fmt.Sprintf("gs://%s/%s", bucket, object)
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(cfg.GCSURI)
if err != nil || u.Scheme != "gs" || u.Host == "" {
    return fmt.Errorf("GCS URI %q must include a bucket, e.g. gs://bucket/path", cfg.GCSURI)
}

Type guard

func hasGCSBucket(uri string) bool {
    u, err := url.Parse(uri)
    return err == nil && u.Scheme == "gs" && u.Host != ""
}

Prevention

When it happens

Trigger: Calling DownloadRecursive or UploadFile with a URI like 'gs://' or 'gs:///path/only' where the authority/bucket part is missing; also with 'gs:///bucket-looks-like-path' forms.

Common situations: Config value for a GCS source or cache left as 'gs://' with no bucket; environment variable for bucket name empty so the URI concatenates to 'gs://' + '' + '/obj'; typo dropping the bucket from the path.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/6e58fbccad9a6371. Report an issue: GitHub.