GoogleContainerTools/skaffold · error

cannot parse URI %q: %w

Error message

cannot parse URI %q: %w

What it means

parseGCSURI wraps url.Parse failures for a GCS URI argument. It means the string passed as src (DownloadRecursive) or dst (UploadFile) is not a syntactically valid URL, so the bucket and object path cannot be extracted. The original url.Error is wrapped with %w.

Source

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

		return err
	}

	dstObj := urinfo.ObjPath
	if isDirectory {
		dstObj, err = url.JoinPath(dstObj, filepath.Base(src))
		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:

View on GitHub (pinned to a1189de023)

Solutions

  1. Print/inspect the wrapped error to find the invalid character and fix the URI string
  2. Escape or remove URL-invalid characters (use url.PathEscape for interpolated segments, or encode brackets)
  3. Ensure the URI has the form gs://bucket/path before passing it in
  4. If using shell interpolation, quote variables: "gs://bucket/${DIR}/**" with DIR free of spaces/special chars

Example fix

// before
n.DownloadRecursive(ctx, "gs://bucket/[release]/config*", dst) // url.Parse fails on '['
// after
uri := "gs://bucket/" + url.PathEscape("[release]") + "/config*"
if err := n.DownloadRecursive(ctx, uri, dst); err != nil { /* handle */ }
Defensive patterns

Strategy: validation

Validate before calling

func validateGCSURISyntax(uri string) error {
	if _, err := url.Parse(uri); err != nil {
		return fmt.Errorf("invalid URI %q: %w", uri, err)
	}
	return nil
}
// or sanitize interpolated values with url.PathEscape before building the URI

Prevention

When it happens

Trigger: Calling Native.DownloadRecursive or Native.UploadFile with a malformed URI string such as "gs://bucket/[dir" (invalid characters like unescaped brackets, spaces or control chars) instead of something like "gs://bucket/dir/**".

Common situations: Config values interpolated from shell variables producing spaces or unescaped characters; globs containing '[' or ']' character classes that url.Parse rejects; Windows paths with backslashes pasted in as dst.

Related errors


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