kubernetes/kops · error

invalid s3 path: %q

Error message

invalid s3 path: %q

What it means

VFSContext.buildS3Path failed to parse the given path as a URL. The vfs layer requires S3 locations to be parseable URLs with the s3:// scheme; when url.Parse errors, it returns this error wrapping the original path.

Source

Thrown at util/pkg/vfs/context.go:349

		}
		noMoreRetries := i >= backoff.Steps
		if !noMoreRetries && err != nil {
			klog.V(2).Infof("retrying after error %v", err)
		}

		if noMoreRetries {
			klog.V(2).Infof("hit maximum retries %d with error %v", i, err)
			return done, err
		}
	}
}

func (c *VFSContext) buildS3Path(p string) (*S3Path, error) {
	endpoint := os.Getenv("S3_ENDPOINT")

	u, err := url.Parse(p)
	if err != nil {
		return nil, fmt.Errorf("invalid s3 path: %q", p)
	}
	if u.Scheme != "s3" {
		return nil, fmt.Errorf("invalid s3 path: %q", p)
	}

	bucket := strings.TrimSuffix(u.Host, "/")
	if bucket == "" {
		return nil, fmt.Errorf("invalid s3 path: %q", p)
	}

	s3path := newS3Path(c.s3Context, u.Scheme, bucket, u.Path, true, func(o *s3.Options) {
		if endpoint != "" {
			o.BaseEndpoint = aws.String(endpoint)
			o.UsePathStyle = true
			o.DisableLogOutputChecksumValidationSkipped = true
		} else {
			o.EndpointResolverV2 = &ResolverV2{}
		}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Print and inspect the exact path in the error message (%q shows escapes); fix the malformed characters or percent-encoding.
  2. URL-escape dynamic components before composing the path, e.g. url.PathEscape for bucket/key segments.
  3. Ensure KOPS_STATE_STORE is set to a plain s3://bucket/path value without control characters or stray quotes.
  4. Set KOPS_STATE_STORE explicitly if it is empty or contains whitespace from the environment.

Example fix

// before
statePath := fmt.Sprintf("s3://%s/state", rawBucketName) // rawBucketName contains "%zz" or a newline
// after
statePath := "s3://" + url.PathEscape(rawBucketName) + "/state"
Defensive patterns

Strategy: validation

Validate before calling

func validS3StorePath(p string) bool {
	u, err := url.Parse(p)
	return err == nil && u.Scheme == "s3" && strings.TrimSuffix(u.Host, "/") != ""
}
if !validS3StorePath(os.Getenv("KOPS_STATE_STORE")) {
	return fmt.Errorf("KOPS_STATE_STORE must be a valid s3://bucket/path URL, got %q", os.Getenv("KOPS_STATE_STORE"))
}

Type guard

func isParsableURL(p string) bool {
	_, err := url.Parse(p)
	return err == nil
}

Try / catch

p, err := vfs.Context.BuildVfsPath(raw)
if err != nil {
	if strings.Contains(err.Error(), "invalid s3 path") {
		return fmt.Errorf("malformed S3 state store %q: %w", raw, err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling BuildVfsPath with a string that url.Parse rejects (e.g. containing control characters, invalid percent-escapes like 's3://bucket/%zz', or unescaped non-ASCII data) so parsing fails before the scheme check.

Common situations: Cluster config or KOPS_STATE_STORE values constructed programmatically (shell interpolation, templating) that inject raw bytes, newlines, or malformed percent-encoding into the store path.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/06082eaef5a27725. Report an issue: GitHub.