{"record":{"id":"6ca9b443a3050f2d","repo":"kubernetes/kops","slug":"required-s3-endpoint-env-var-for-path-q","errorCode":null,"errorMessage":"required S3_ENDPOINT env var for path: %q","messagePattern":"required S3_ENDPOINT env var for path: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/vfs/context.go","lineNumber":375,"sourceCode":"\t\treturn nil, fmt.Errorf(\"invalid s3 path: %q\", p)\n\t}\n\n\ts3path := newS3Path(c.s3Context, u.Scheme, bucket, u.Path, true, func(o *s3.Options) {\n\t\tif endpoint != \"\" {\n\t\t\to.BaseEndpoint = aws.String(endpoint)\n\t\t\to.UsePathStyle = true\n\t\t\to.DisableLogOutputChecksumValidationSkipped = true\n\t\t} else {\n\t\t\to.EndpointResolverV2 = &ResolverV2{}\n\t\t}\n\t})\n\treturn s3path, nil\n}\n\nfunc (c *VFSContext) buildDOPath(p string) (*S3Path, error) {\n\tendpoint := os.Getenv(\"S3_ENDPOINT\")\n\tif endpoint == \"\" {\n\t\treturn nil, fmt.Errorf(\"required S3_ENDPOINT env var for path: %q\", p)\n\t}\n\n\tu, err := url.Parse(p)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid spaces path: %q\", p)\n\t}\n\tif u.Scheme != \"do\" {\n\t\treturn nil, fmt.Errorf(\"invalid spaces path: %q\", p)\n\t}\n\n\tbucket := strings.TrimSuffix(u.Host, \"/\")\n\tif bucket == \"\" {\n\t\treturn nil, fmt.Errorf(\"invalid spaces path: %q\", p)\n\t}\n\n\ts3path := newS3Path(c.s3Context, u.Scheme, bucket, u.Path, false, func(o *s3.Options) {\n\t\to.BaseEndpoint = aws.String(endpoint)\n\t\to.UsePathStyle = true","sourceCodeStart":357,"sourceCodeEnd":393,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/vfs/context.go#L357-L393","documentation":"buildDOPath requires the S3_ENDPOINT environment variable because DigitalOcean Spaces is an S3-compatible endpoint whose URL cannot be derived from the bucket name alone. When S3_ENDPOINT is unset or empty and a do:// path is requested, the VFS layer returns this error.","triggerScenarios":"Calling BuildVfsPath with a do://... path while os.Getenv(\"S3_ENDPOINT\") returns \"\" — e.g. using kops with KOPS_STATE_STORE=do://bucket without exporting S3_ENDPOINT.","commonSituations":"DigitalOcean Spaces users forgetting S3_ENDPOINT=https://nyc3.digitaloceanspaces.com in the shell profile or CI job; endpoint lost when running kops in a container or cron with a minimal environment.","solutions":["Export S3_ENDPOINT to your region's Spaces endpoint, e.g. export S3_ENDPOINT=https://nyc3.digitaloceanspaces.com.","Add S3_ENDPOINT to CI/container/cron environments where the interactive shell profile is not sourced.","Confirm with `echo $S3_ENDPOINT` in the same shell that runs kops.","Verify the region in the endpoint matches the region where the Space was created."],"exampleFix":"// before\nexport KOPS_STATE_STORE=do://my-space/clusters   # S3_ENDPOINT unset\n// after\nexport S3_ENDPOINT=https://nyc3.digitaloceanspaces.com\nexport KOPS_STATE_STORE=do://my-space/clusters","handlingStrategy":"validation","validationCode":"if os.Getenv(\"S3_ENDPOINT\") == \"\" {\n\treturn errors.New(\"S3_ENDPOINT is required for do:// state stores, e.g. https://nyc3.digitaloceanspaces.com\")\n}","typeGuard":null,"tryCatchPattern":"p, err := vfs.Context.BuildVfsPath(raw)\nif err != nil {\n\tif strings.Contains(err.Error(), \"required S3_ENDPOINT\") {\n\t\treturn fmt.Errorf(\"export S3_ENDPOINT (e.g. https://nyc3.digitaloceanspaces.com) before using %q\", raw)\n\t}\n\treturn err\n}","preventionTips":["Export S3_ENDPOINT alongside KOPS_STATE_STORE for Spaces/Linode.","Add S3_ENDPOINT to CI secrets, container env, and cron environments.","Verify with `echo $S3_ENDPOINT` in the same shell that runs kops.","Match the endpoint region to the bucket's region."],"tags":["digitalocean","spaces","env-var","s3-compatible","vfs"],"backgroundTag":"missing-env-var","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"}