{"record":{"id":"a18c83651cd22676","repo":"kubernetes/kops","slug":"escaping-nodeup-source-q-w","errorCode":null,"errorMessage":"escaping nodeup source %q: %w","messagePattern":"escaping nodeup source %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/resources/nodeup.go","lineNumber":276,"sourceCode":"\tasset := b.NodeUpAssets[arch]\n\tif asset == nil {\n\t\treturn \"\", nil\n\t}\n\n\tlocations := slices.Clone(asset.Locations)\n\tfor i, location := range locations {\n\t\tvar escape func(string) (string, error)\n\t\tswitch {\n\t\tcase strings.HasPrefix(location, \"s3://\"):\n\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","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/resources/nodeup.go#L258-L294","documentation":"nodeUpSource wraps any failure from the per-scheme escape function (escapeS3Location or escapeBlobLocation) when preparing the nodeup download source URLs. It indicates that one of the configured NodeUpSource locations could not be parsed or escaped into a safe form for embedding in the nodeup bootstrap script. The wrapped inner error carries the specific cause.","triggerScenarios":"Calling Build (directly or via GetBootstrapData/renderNodeUpScript/kubeEnv) while a NodeUpSource location for the target architecture uses the s3:// or azureblob:// scheme and that location either fails url.Parse or is rejected by the scheme's escape validator.","commonSituations":"Typos or malformed URLs in the cluster spec (e.g. 's3://bucket path/key' with spaces, missing bucket), wrong scheme casing, or an azureblob:// URL with query strings or credentials pasted from the portal.","solutions":["Inspect the wrapped inner error for the actual parse/validation failure.","Print and fix the NodeUpSource location value in the cluster spec so it is a well-formed s3://bucket/key or azureblob://account/container/key URL.","If constructing locations programmatically, validate with url.Parse before passing them in.","Re-run kops update/apply after correcting the source."],"exampleFix":"// before\nNodeUpSource: \"s3://my bucket/kops/linux/amd64/nodeup\"\n// after\nNodeUpSource: \"s3://my-bucket/kops/linux/amd64/nodeup\"","handlingStrategy":"validation","validationCode":"for _, loc := range strings.Split(nodeUpSource, \",\") {\n    if _, err := url.Parse(strings.TrimSpace(loc)); err != nil {\n        return fmt.Errorf(\"invalid nodeup source %q: %w\", loc, err)\n    }\n}","typeGuard":"func isValidURL(loc string) bool { _, err := url.Parse(loc); return err == nil }","tryCatchPattern":"src, err := b.nodeUpSource(arch)\nif err != nil {\n    return fmt.Errorf(\"nodeup source invalid, check s3://azureblob:// URLs: %w\", err)\n}","preventionTips":["Validate all nodeup source URLs with url.Parse before applying","Never hand-edit URLs into cluster specs; generate them programmatically","Keep bucket/container names free of spaces and special characters"],"tags":["nodeup","url-parsing","bootstrap"],"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-12T07:17:12.445Z"}