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

  1. Set both the endpoint and bucket (e.g. S3_BUCKET or Config.Bucket) to non-empty trimmed values.
  2. Check whitespace-only values — TrimSpace means ' ' still fails.
  3. If constructing Config directly, populate Endpoint and Bucket before calling New.
  4. 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

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


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)