{"record":{"id":"c83b57d238316f11","repo":"kubernetes/kops","slug":"invalid-azure-blob-location-expected-azureblob","errorCode":null,"errorMessage":"invalid Azure Blob location; expected azureblob://<account>/<container>/<key>","messagePattern":"invalid Azure Blob location; expected azureblob://<account>/<container>/<key>","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/resources/nodeup.go","lineNumber":304,"sourceCode":"\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>\")\n\t}\n\n\treturn \"azureblob://\" + u.Host + httpbinding.EscapePath(u.Path, false), nil\n}\n\nfunc (b *NodeUpScript) Build() (fi.Resource, error) {\n\tif b.ProxyEnv == nil {\n\t\tb.ProxyEnv = funcEmptyString\n\t}\n\tif b.EnvironmentVariables == nil {\n\t\tb.EnvironmentVariables = funcEmptyString\n\t}\n\n\tif b.useS3Download() && b.S3Region == \"\" {\n\t\treturn nil, fmt.Errorf(\"ResolveS3Region must be called before building a nodeup script with an s3:// source\")\n\t}\n\n\tif b.useBlobDownload() {","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/resources/nodeup.go#L286-L322","documentation":"escapeBlobLocation validates that the azureblob:// URL is representable by the account-based blob.core.windows.net URL nodeup downloads from: correct scheme, non-empty host, no port or IPv6-style host, no userinfo, no query, no fragment, and both container and key present. Anything violating these constraints returns this descriptive error so it fails early rather than in the node boot retry loop.","triggerScenarios":"A nodeup source like 'azureblob://account:443/container/key' (port), 'azureblob://user@account/container/key' (userinfo), 'azureblob://account/container/key?sig=...' (query), 'azureblob://account/container#frag' (fragment), or a URL missing the container or key segment.","commonSituations":"Copying a full portal/SAS blob URL instead of building the azureblob:// form; using a sovereign-cloud endpoint URL; omitting the container so the path has only one segment.","solutions":["Reformat the location as exactly azureblob://<account>/<container>/<key>.","Remove query strings, fragments, ports, and userinfo from the URL.","Ensure the path has both a container and a key segment after the leading slash.","If on a sovereign cloud, note the script only supports the public cloud endpoint — see the AZURE_ENVIRONMENT check (error 1406)."],"exampleFix":"// before\nNodeUpSource: \"azureblob://myaccount/mycontainer/nodeup?sv=2020-02-10&sig=abc\"\n// after\nNodeUpSource: \"azureblob://myaccount/mycontainer/artifacts/linux/amd64/nodeup\"","handlingStrategy":"validation","validationCode":"func validAzureBlob(loc string) error {\n    u, err := url.Parse(loc)\n    if err != nil { return err }\n    c, k, _ := strings.Cut(strings.TrimPrefix(u.Path, \"/\"), \"/\")\n    if u.Scheme != \"azureblob\" || u.Host == \"\" || u.Hostname() != u.Host ||\n        u.User != nil || u.RawQuery != \"\" || u.Fragment != \"\" || c == \"\" || k == \"\" {\n        return errors.New(\"expected azureblob://<account>/<container>/<key>\")\n    }\n    return nil\n}","typeGuard":"func isPlainAzureBlobURL(loc string) bool { return validAzureBlob(loc) == nil }","tryCatchPattern":"if err := validAzureBlob(loc); err != nil {\n    return fmt.Errorf(\"reformat blob source as azureblob://account/container/key: %w\", err)\n}","preventionTips":["Enforce the azureblob://<account>/<container>/<key> shape at config-load time","Reject URLs containing ?, #, @, or :port early","Document the expected format wherever blob sources are configured"],"tags":["azure","validation","nodeup"],"backgroundTag":"invalid-azureblob-url","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"}