JuliusBrussee/caveman · critical
objectstore: S3_ENDPOINT is required in production
Error message
objectstore: S3_ENDPOINT is required in production
What it means
FromEnv returns this error when S3_ENDPOINT is empty and the process is running in production (env.IsProduction()). In production the object store must be explicitly configured — silently defaulting to a local bucket would be unsafe — while in non-production it returns (nil, nil) meaning 'no store configured'.
Solutions
- Set S3_ENDPOINT to the MinIO/S3 endpoint URL in the deployment environment.
- Confirm the deployment manifest/secret actually injects S3_ENDPOINT into the container env.
- Check env.IsProduction(): if this is not meant to be production, fix the environment flag rather than the S3 vars.
- If intentionally running without a store in non-production, set the endpoint or accept the (nil, nil) store and guard usage.
Example fix
// before (k8s env)
# S3_ENDPOINT missing
// after
env:
- name: S3_ENDPOINT
value: "minio.internal.example.com:9000" Defensive patterns
Strategy: validation
Validate before calling
if os.Getenv("S3_ENDPOINT") == "" && env.IsProduction() {
return errors.New("refusing to start: S3_ENDPOINT required in production")
} Try / catch
store, err := objectstore.FromEnv()
if err != nil {
return fmt.Errorf("object store init: %w", err)
} Prevention
- Add S3_ENDPOINT to deployment secrets/configmaps and startup readiness checks
- Validate required env vars in CI with a production-mode smoke test
- Distinguish the intentional (nil, nil) non-production case from the production error
- Document env var names where config is templated
When it happens
Trigger: Deploying a service with S3_ENDPOINT unset/empty while the production environment flag is active (e.g. CAVE_ENV=production); a mis-deployed config where the env var was dropped; running the production binary locally without realizing it detects production mode.
Common situations: Kubernetes/container deploys missing the S3_ENDPOINT entry in the secret or configmap; renaming the env var during a config refactor; CI jobs running with production env flags but no S3 settings.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- cave_claude_model_required
- caveman-code: no supported provider credential found; set…
- invalid CAVEMAN_LISTEN
- invalid listener
- objectstore: access key and secret key are required
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/6687a68d8372383e.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/objectstore/objectstore.go:147
AccessKey string
SecretKey string
Region string
UseSSL bool
}
// FromEnv builds a Store from the S3_* environment variables. It returns
// (nil, nil) when S3_ENDPOINT is unset outside production. Production requires
// object storage because retention, replay, and artifact offload must not
// silently disable themselves after launch.
//
// Credential vars accept both the repo's names (S3_ACCESS_KEY/S3_SECRET_KEY)
// and the AWS-conventional names (S3_ACCESS_KEY_ID/S3_SECRET_ACCESS_KEY). TLS is
// inferred from the endpoint scheme (https) unless S3_USE_SSL forces it.
func FromEnv() (Store, error) {
endpoint := env.String("S3_ENDPOINT", "")
if endpoint == "" {
if env.IsProduction() {
return nil, errors.New("objectstore: S3_ENDPOINT is required in production")
}
return nil, nil
}
production := env.IsProduction()
bucketFallback := "caveman-local"
if production {
bucketFallback = ""
}
access := env.String("S3_ACCESS_KEY", env.String("S3_ACCESS_KEY_ID", ""))
secret := env.String("S3_SECRET_KEY", env.String("S3_SECRET_ACCESS_KEY", ""))
useSSL := strings.HasPrefix(endpoint, "https://") || env.Bool("S3_USE_SSL", false)
cfg := Config{
Endpoint: endpoint,
Bucket: env.String("S3_BUCKET", bucketFallback),
AccessKey: access,
SecretKey: secret,
Region: env.String("S3_REGION", "us-east-1"),
UseSSL: useSSL,View on GitHub (pinned to 3ee70a1026)