{"record":{"id":"07635e926c6c4c57","repo":"kubernetes/kops","slug":"parsing-s3-location-w","errorCode":null,"errorMessage":"parsing S3 location: %w","messagePattern":"parsing S3 location: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/resources/nodeup.go","lineNumber":286,"sourceCode":"\t\t\tescape = escapeS3Location\n\t\tcase strings.HasPrefix(location, \"azureblob://\"):\n\t\t\tescape = escapeBlobLocation\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t\tescaped, err := escape(location)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"escaping nodeup source %q: %w\", location, err)\n\t\t}\n\t\tlocations[i] = escaped\n\t}\n\treturn strings.Join(locations, \",\"), nil\n}\n\nfunc escapeS3Location(location string) (string, error) {\n\tu, err := url.Parse(location)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"parsing S3 location: %w\", err)\n\t}\n\tif u.Scheme != \"s3\" || u.Host == \"\" {\n\t\treturn \"\", fmt.Errorf(\"invalid S3 location\")\n\t}\n\n\treturn \"s3://\" + u.Host + httpbinding.EscapePath(u.Path, false), nil\n}\n\nfunc escapeBlobLocation(location string) (string, error) {\n\tu, err := url.Parse(location)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"parsing Azure Blob location: %w\", err)\n\t}\n\tcontainer, key, _ := strings.Cut(strings.TrimPrefix(u.Path, \"/\"), \"/\")\n\t// Reject ports, IPv6 hosts, userinfo, queries, and fragments, which the account-based\n\t// blob.core.windows.net URL cannot represent, so they fail here instead of in the boot retry loop.\n\tif u.Scheme != \"azureblob\" || u.Host == \"\" || u.Hostname() != u.Host || u.User != nil || u.RawQuery != \"\" || u.Fragment != \"\" || container == \"\" || key == \"\" {\n\t\treturn \"\", fmt.Errorf(\"invalid Azure Blob location; expected azureblob://<account>/<container>/<key>\")","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/resources/nodeup.go#L268-L304","documentation":"escapeS3Location parses the S3 URL with url.Parse before re-escaping the path via httpbinding.EscapePath. This error is thrown when Go's url.Parse rejects the location string, meaning it is not a syntactically valid URL at all.","triggerScenarios":"A nodeup source location with the s3:// scheme that contains characters invalid for url.Parse, such as raw spaces, unescaped control characters, or a malformed authority (e.g. 's3://bucket:/key' variants that trip the parser).","commonSituations":"Hand-edited nodeup source values, templating mistakes that leave whitespace or newlines in the URL, or copy-paste artifacts like trailing spaces or embedded quotes.","solutions":["Read the wrapped url.Parse error to see the offending position.","Fix the S3 URL so it is a valid URL: s3://<bucket>/<key> with no spaces or control characters.","If the location is assembled dynamically, percent-escape or sanitize its components first.","Verify with `url.Parse` in a small Go snippet or `kops toolbox` that the URL parses."],"exampleFix":"// before\nlocation := fmt.Sprintf(\"s3://%s/nodeup\", bucketNameWithSpace)\n// after\nlocation := fmt.Sprintf(\"s3://%s/nodeup\", strings.ReplaceAll(bucketName, \" \", \"-\"))","handlingStrategy":"validation","validationCode":"u, err := url.Parse(location)\nif err != nil {\n    return fmt.Errorf(\"s3 location not a valid URL: %w\", err)\n}","typeGuard":"func parsesAsURL(s string) bool { _, err := url.Parse(s); return err == nil }","tryCatchPattern":"escaped, err := escapeS3Location(loc)\nif err != nil {\n    return fmt.Errorf(\"fix s3:// URL syntax (%v): %w\", loc, err)\n}","preventionTips":["Percent-escape dynamic path segments before composing the URL","Trim whitespace/newlines from config values before use","Test generated URLs in a unit test with url.Parse"],"tags":["s3","url-parsing","nodeup"],"backgroundTag":"invalid-url-location","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}