{"record":{"id":"0525f89f736a8563","repo":"kubernetes/kops","slug":"resolves3region-must-be-called-before-building-a-n","errorCode":null,"errorMessage":"ResolveS3Region must be called before building a nodeup script with an s3:// source","messagePattern":"ResolveS3Region must be called before building a nodeup script with an s3:// source","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/resources/nodeup.go","lineNumber":319,"sourceCode":"\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() {\n\t\t// The script hard-codes the public cloud blob.core.windows.net endpoint suffix.\n\t\t// Azure environment names are case-insensitive; AzureCloud is the CLI name of the public cloud.\n\t\tif azureEnv := os.Getenv(\"AZURE_ENVIRONMENT\"); azureEnv != \"\" && !strings.EqualFold(azureEnv, \"AzurePublicCloud\") && !strings.EqualFold(azureEnv, \"AzureCloud\") {\n\t\t\treturn nil, fmt.Errorf(\"downloading nodeup from an azureblob:// URL is not supported in Azure environment %q\", azureEnv)\n\t\t}\n\t}\n\n\tfunctions := template.FuncMap{\n\t\t\"NodeUpSourceAmd64\": func() (string, error) {\n\t\t\treturn b.nodeUpSource(architectures.ArchitectureAmd64)\n\t\t},\n\t\t\"NodeUpSourceHashAmd64\": func() string {\n\t\t\tif b.NodeUpAssets[architectures.ArchitectureAmd64] != nil {\n\t\t\t\treturn b.NodeUpAssets[architectures.ArchitectureAmd64].Hash.Hex()\n\t\t\t}","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/resources/nodeup.go#L301-L337","documentation":"Build refuses to render the nodeup script when the source uses the s3:// scheme but b.S3Region was never populated. S3 downloads require a region for the bootstrap endpoint, and kops makes the caller (e.g. GetBootstrapData) invoke ResolveS3Region first; this error is the guard against forgetting that step.","triggerScenarios":"Calling Build, GetBootstrapData, or kubeEnv on a NodeUpScript whose NodeUpSource contains an s3:// location without first calling ResolveS3Region(ctx) on the same NodeUpScript instance.","commonSituations":"New integration code or tests constructing resources.NodeUpScript directly and skipping the ResolveS3Region call that the normal kops apply flow performs; refactors that reorder construction and resolution.","solutions":["Call nodeUpScript.ResolveS3Region(ctx) before Build when using an s3:// source.","If you construct NodeUpScript yourself, replicate the order used in the apply path: build VFS path, resolve region, then Build.","For non-S3 sources this check is skipped — confirm the source really should be s3://.","Update custom tooling/tests to follow the documented sequence."],"exampleFix":"// before\nscript := &resources.NodeUpScript{NodeUpSource: \"s3://bucket/nodeup\"}\nfi, err := script.Build(arch)\n// after\nscript := &resources.NodeUpScript{NodeUpSource: \"s3://bucket/nodeup\"}\nif err := script.ResolveS3Region(ctx); err != nil { return err }\nfi, err := script.Build(arch)","handlingStrategy":"try-catch","validationCode":"if b.useS3Download() && b.S3Region == \"\" {\n    if err := b.ResolveS3Region(ctx); err != nil { return err }\n}","typeGuard":"func s3RegionResolved(b *resources.NodeUpScript) bool { return b.S3Region != \"\" }","tryCatchPattern":"if err := script.ResolveS3Region(ctx); err != nil {\n    return fmt.Errorf(\"resolve S3 region before Build: %w\", err)\n}\nfi, err := script.Build(arch)","preventionTips":["Always call ResolveS3Region before Build when sources use s3://","Wrap Build in a helper that performs the resolution step","Add a unit test asserting the call order"],"tags":["s3","region","initialization-order","nodeup"],"backgroundTag":"missing-region-resolution","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"}