JuliusBrussee/caveman · error
objectstore: endpoint and bucket are required
Error message
objectstore: endpoint and bucket are required
What it means
validateConfig rejects a Config whose Endpoint or Bucket is blank. A MinIO/S3 store cannot be constructed without knowing where to connect and which bucket to use, so FromEnv/validateConfig fail fast with this error before any network call.
Solutions
- Set both the endpoint and bucket (e.g. S3_BUCKET or Config.Bucket) to non-empty trimmed values.
- Check whitespace-only values — TrimSpace means ' ' still fails.
- If constructing Config directly, populate Endpoint and Bucket before calling New.
- For production, rely on the documented env names rather than the local 'caveman-local' fallback, which only applies in non-production.
Example fix
// before
store, err := objectstore.New(objectstore.Config{Endpoint: "minio:9000"})
// after
store, err := objectstore.New(objectstore.Config{
Endpoint: "minio:9000",
Bucket: "caveman-artifacts",
}) Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(cfg.Endpoint) == "" || strings.TrimSpace(cfg.Bucket) == "" {
return errors.New("endpoint and bucket must be set")
} Try / catch
store, err := objectstore.New(cfg)
if err != nil {
return fmt.Errorf("object store config invalid: %w", err)
} Prevention
- Set both S3_ENDPOINT and S3_BUCKET in every environment
- Remember TrimSpace: whitespace-only values still fail
- Rely on the local bucket fallback only outside production
- Validate Config structs before calling New in code paths that build them programmatically
When it happens
Trigger: Calling objectstore.New with Config{Endpoint:""} or Config{Bucket:""}; FromEnv with S3_ENDPOINT set (so it proceeds past the production check) but the bucket missing/unresolvable in production; whitespace-only values (they are TrimSpace'd, so ' ' also triggers it).
Common situations: Setting S3_ENDPOINT but forgetting S3_BUCKET; building a Config programmatically and leaving Bucket zero-valued; production deploys where the bucket-fallback logic is skipped and no explicit bucket var is set.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- apiKey, baseURL, and agent are required
- ASGI context resolver or request bounds are invalid
- bedrock endpoint must be runtime or mantle
- cave_mastra_max_steps_invalid
- cave_memory_agent_invalid
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/14c0cd72dc637f2c.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/objectstore/objectstore.go:190
return nil, err
}
if production {
timeout := time.Duration(env.Int("CAVE_OBJECTSTORE_PROBE_TIMEOUT_MS", 10000)) * time.Millisecond
if timeout <= 0 {
timeout = 10 * time.Second
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
if err := Probe(ctx, store); err != nil {
return nil, fmt.Errorf("objectstore: production read/write/delete probe failed: %w", err)
}
}
return store, nil
}
func validateConfig(cfg Config, production bool) error {
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")
}View on GitHub (pinned to 3ee70a1026)