benbjohnson/litestream · error

invalid s3 access point url: %s

Error message

invalid s3 access point url: %s

What it means

parseS3AccessPointURL handles s3://arn:... Access Point URLs; if the string does not start with the s3:// prefix it cannot be an S3 Access Point URL and this error is returned. It guards the ARN-parsing path from non-S3 inputs.

Source

Thrown at replica_url.go:114

	case "file":
		scheme, u.Scheme = u.Scheme, ""
		// Remove query params from path for file URLs
		u.RawQuery = ""
		return scheme, "", path.Clean(u.String()), nil, nil, nil

	case "":
		return u.Scheme, u.Host, u.Path, nil, nil, fmt.Errorf("replica url scheme required: %s", s)

	default:
		return u.Scheme, u.Host, strings.TrimPrefix(path.Clean(u.Path), "/"), u.Query(), u.User, nil
	}
}

// parseS3AccessPointURL parses an S3 Access Point URL (s3://arn:...).
func parseS3AccessPointURL(s string) (scheme, host, urlPath string, query url.Values, err error) {
	const prefix = "s3://"
	if !strings.HasPrefix(strings.ToLower(s), prefix) {
		return "", "", "", nil, fmt.Errorf("invalid s3 access point url: %s", s)
	}

	arnWithPath := s[len(prefix):]

	// Split off query string if present
	var queryStr string
	if idx := strings.IndexByte(arnWithPath, '?'); idx != -1 {
		queryStr = arnWithPath[idx+1:]
		arnWithPath = arnWithPath[:idx]
	}

	bucket, key, err := splitS3AccessPointARN(arnWithPath)
	if err != nil {
		return "", "", "", nil, err
	}

	// Parse query string if present
	if queryStr != "" {

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Ensure the Access Point URL is exactly s3://arn:aws:s3:<region>:<acct>:accesspoint/<name>/... .
  2. Use a plain bucket URL (s3://bucket/path) instead of an ARN if you don't need Access Points.
  3. Check for transcription/normalization bugs that altered the s3:// prefix.
  4. Confirm you're not passing a gs:// or other scheme URL into the S3 Access Point code path.

Example fix

// before
url = "arn:aws:s3:us-east-1:123456789012:accesspoint/myap/db" // invalid s3 access point url
// after
url = "s3://arn:aws:s3:us-east-1:123456789012:accesspoint/myap/db"
Defensive patterns

Strategy: validation

Validate before calling

if strings.Contains(replicaURL, "arn:") && !strings.HasPrefix(strings.ToLower(replicaURL), "s3://arn:") {
    return fmt.Errorf("access point ARN URLs must start with s3://arn:")
}

Type guard

func isS3AccessPointURL(s string) bool { return strings.HasPrefix(strings.ToLower(s), "s3://arn:") }

Try / catch

if _, err := litestream.ParseReplicaURL(rawURL); err != nil {
    if strings.Contains(err.Error(), "invalid s3 access point url") { return fmt.Errorf("bad access point URL %q: must be s3://arn:aws:s3:...", rawURL) }
    return err
}

Prevention

When it happens

Trigger: Calling ParseReplicaURL/ParseReplicaURLWithQuery on a string starting with a case-normalized match for the ARN path but not literally s3:// — practically this occurs when callers invoke parseS3AccessPointURL (via the ARN dispatch) with a URL whose scheme differs, e.g. passing an ARN with a different scheme or a mutated string.

Common situations: Copy-pasting an S3 Access Point ARN and altering the scheme; using s3a:// or vendor-compatible endpoints where the Access Point path was expected; string processing that stripped or lowercased the s3:// prefix inconsistently.

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 benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/3c522508877f1385. Report an issue: GitHub.