JuliusBrussee/caveman · error
objectstore: production endpoint must be an HTTPS origin…
Error message
objectstore: production endpoint must be an HTTPS origin without credentials, path, query, or fragment
What it means
In production, validateConfig parses the endpoint as a URL and requires it to be a clean HTTPS origin: scheme https, non-empty hostname, no userinfo (credentials embedded in URL), no query string, no fragment, and a path that is empty or exactly '/'. Anything else is rejected to prevent malformed or credential-leaking endpoints reaching the S3 client.
Solutions
- Use a bare HTTPS origin: scheme https, hostname only, optional trailing '/', no credentials/query/fragment/path prefix.
- Move credentials out of the URL into S3_ACCESS_KEY / S3_SECRET_ACCESS_KEY.
- If a path prefix is genuinely needed (e.g. reverse proxy), configure it at the network/DNS level or drop it — the S3 path must be the origin root.
- Validate the endpoint string with url.Parse in your deploy tooling before rollout.
Example fix
// before S3_ENDPOINT=https://user:pass@minio.internal/artifacts // after S3_ENDPOINT=https://minio.internal # credentials via S3_ACCESS_KEY / S3_SECRET_ACCESS_KEY
Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(cfg.Endpoint)
if err != nil || u.Scheme != "https" || u.Hostname() == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" || (u.Path != "" && u.Path != "/") {
return errors.New("endpoint must be a bare HTTPS origin")
} Try / catch
store, err := objectstore.New(cfg)
if err != nil {
return fmt.Errorf("object store endpoint invalid: %w", err)
} Prevention
- Use bare https origins (host[:port]) in S3_ENDPOINT — no paths, query, fragments, or userinfo
- Never embed credentials in the endpoint URL; use access/secret keys
- Validate endpoint URLs in deploy tooling before rollout
When it happens
Trigger: Endpoint like https://user:pass@host, https://host/some/prefix, https://host?x=1, or https://host#frag in production; a URL that fails url.Parse or whose scheme resolves to non-https (e.g. http:// despite UseSSL); endpoint missing a hostname entirely.
Common situations: Embedding credentials in the endpoint URL instead of using access/secret keys; pointing at an S3 path-style URL with a bucket in the path; proxy URLs with query parameters pasted into S3_ENDPOINT.
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
- objectstore: production requires TLS
- backslash is not allowed in path
- cave_gateway_identity_unverified
- dot segments are not allowed in path
- invalid CAVEMAN_LISTEN
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/9a13155e4a91192f.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/objectstore/objectstore.go:207
if strings.TrimSpace(cfg.Endpoint) == "" || strings.TrimSpace(cfg.Bucket) == "" {
return errors.New("objectstore: endpoint and bucket are required")
}
if strings.TrimSpace(cfg.AccessKey) == "" || strings.TrimSpace(cfg.SecretKey) == "" {
return errors.New("objectstore: access key and secret key are required")
}
if !production {
return nil
}
if !cfg.UseSSL || strings.HasPrefix(strings.ToLower(strings.TrimSpace(cfg.Endpoint)), "http://") {
return errors.New("objectstore: production requires TLS")
}
raw := strings.TrimSpace(cfg.Endpoint)
if !strings.Contains(raw, "://") {
raw = "https://" + raw
}
u, err := url.Parse(raw)
if err != nil || u.Scheme != "https" || u.Hostname() == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" || (u.Path != "" && u.Path != "/") {
return errors.New("objectstore: production endpoint must be an HTTPS origin without credentials, path, query, or fragment")
}
return nil
}
// New constructs a MinIO/S3-backed Store. FromEnv adds a live production probe.
func New(cfg Config) (Store, error) {
endpoint := strings.TrimPrefix(strings.TrimPrefix(cfg.Endpoint, "https://"), "http://")
client, err := minio.New(endpoint, &minio.Options{
Creds: credentials.NewStaticV4(cfg.AccessKey, cfg.SecretKey, ""),
Secure: cfg.UseSSL,
Region: cfg.Region,
})
if err != nil {
return nil, fmt.Errorf("objectstore: minio client: %w", err)
}
return &minioStore{client: client, bucket: cfg.Bucket}, nil
}
View on GitHub (pinned to 3ee70a1026)