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
- Print/inspect the wrapped error to find the invalid character and fix the URI string
- Escape or remove URL-invalid characters (use url.PathEscape for interpolated segments, or encode brackets)
- Ensure the URI has the form gs://bucket/path before passing it in
- 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
- Escape shell/user-provided path segments with url.PathEscape
- Avoid unescaped brackets/spaces in glob patterns
- Log the exact URI string when a parse error occurs
- Centralize URI construction in one helper
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
- URI scheme is %q, must be 'gs'
- bucket name is empty
- %v is not a valid GCS path
- cannot add an empty image value
- CONFIG_REMOTE_REPO_CACHE_NOT_FOUND_ERR
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/642b5b255ac1b0ad.
Report an issue: GitHub.