{"record":{"id":"5cf17490d72a874a","repo":"hasura/graphql-engine","slug":"unable-to-parse-uri-w","errorCode":null,"errorMessage":"unable to parse uri: %w","messagePattern":"unable to parse uri: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/plugins/util.go","lineNumber":150,"sourceCode":"\n\tfor _, platform := range platforms {\n\t\tif platform.Selector == currSelector {\n\t\t\treturn platform, true, nil\n\t\t}\n\t}\n\n\treturn Platform{}, false, nil\n}\n\n// downloadAndExtract downloads the specified archive uri (or uses the provided overrideFile, if a non-empty value)\n// while validating its checksum with the provided sha256sum, and extracts its contents to extractDir that must be.\n// created.\nfunc downloadAndExtract(extractDir, uri, sha256sum string) error {\n\tvar op errors.Op = \"plugins.downloadAndExtract\"\n\n\tnurl, err := url.Parse(uri)\n\tif err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"unable to parse uri: %w\", err))\n\t}\n\n\tvar fetcher download.Fetcher\n\tif nurl.Scheme == \"file\" {\n\t\tfetcher = download.NewFileFetcher(nurl.Path)\n\t} else {\n\t\tfetcher = download.HTTPFetcher{}\n\t}\n\n\tverifier := download.NewSha256Verifier(sha256sum)\n\n\terr = download.NewDownloader(verifier, fetcher).Get(uri, extractDir)\n\tif err != nil {\n\t\treturn errors.E(op, fmt.Errorf(\"failed to unpack the plugin archive: %w\", err))\n\t}\n\n\treturn nil\n}","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/plugins/util.go#L132-L168","documentation":"downloadAndExtract parses the platform's download URI with url.Parse before choosing a fetcher (file:// uses NewFileFetcher, otherwise a network fetcher). If url.Parse returns an error the URI is unusable and the failure is wrapped. This runs during installPlugin, after validation.","triggerScenarios":"installPlugin → downloadAndExtract receiving a URI with invalid percent-encoding (e.g. \"%zz\"), control characters, or otherwise malformed URL syntax that Go's url.Parse rejects.","commonSituations":"Unescaped spaces or % characters in the release URL, URLs assembled via string concatenation without url.PathEscape, or trailing whitespace/newlines pasted into the manifest.","solutions":["Fix the URI in the manifest: ensure valid percent-encoding and no stray whitespace/control characters.","Build URLs programmatically with net/url (url.Parse + Query/Set) instead of string concatenation.","Test with url.Parse(uri) locally before publishing the manifest."],"exampleFix":"// before\n\"url\": \"https://example.com/rele ases/my plugin.tar.gz\"\n\n// after\n\"url\": \"https://example.com/releases/my-plugin.tar.gz\"","handlingStrategy":"validation","validationCode":"if _, err := url.Parse(uri); err != nil {\n\treturn fmt.Errorf(\"bad uri in manifest: %w\", err)\n}","typeGuard":"func isParsableURI(uri string) bool {\n\t_, err := url.Parse(uri)\n\treturn err == nil\n}","tryCatchPattern":null,"preventionTips":["Build URLs with net/url helpers and proper escaping instead of string concatenation.","Trim whitespace when parsing manifests.","Fuzz-test generated URLs through url.Parse in tests."],"tags":["plugins","url","parsing","download"],"backgroundTag":"url-parse-failed","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}