{"record":{"id":"14c0cd72dc637f2c","repo":"JuliusBrussee/caveman","slug":"objectstore-endpoint-and-bucket-are-required","errorCode":null,"errorMessage":"objectstore: endpoint and bucket are required","messagePattern":"objectstore: endpoint and bucket are required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/objectstore/objectstore.go","lineNumber":190,"sourceCode":"\t\treturn nil, err\n\t}\n\tif production {\n\t\ttimeout := time.Duration(env.Int(\"CAVE_OBJECTSTORE_PROBE_TIMEOUT_MS\", 10000)) * time.Millisecond\n\t\tif timeout <= 0 {\n\t\t\ttimeout = 10 * time.Second\n\t\t}\n\t\tctx, cancel := context.WithTimeout(context.Background(), timeout)\n\t\tdefer cancel()\n\t\tif err := Probe(ctx, store); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"objectstore: production read/write/delete probe failed: %w\", err)\n\t\t}\n\t}\n\treturn store, nil\n}\n\nfunc validateConfig(cfg Config, production bool) error {\n\tif strings.TrimSpace(cfg.Endpoint) == \"\" || strings.TrimSpace(cfg.Bucket) == \"\" {\n\t\treturn errors.New(\"objectstore: endpoint and bucket are required\")\n\t}\n\tif strings.TrimSpace(cfg.AccessKey) == \"\" || strings.TrimSpace(cfg.SecretKey) == \"\" {\n\t\treturn errors.New(\"objectstore: access key and secret key are required\")\n\t}\n\tif !production {\n\t\treturn nil\n\t}\n\tif !cfg.UseSSL || strings.HasPrefix(strings.ToLower(strings.TrimSpace(cfg.Endpoint)), \"http://\") {\n\t\treturn errors.New(\"objectstore: production requires TLS\")\n\t}\n\traw := strings.TrimSpace(cfg.Endpoint)\n\tif !strings.Contains(raw, \"://\") {\n\t\traw = \"https://\" + raw\n\t}\n\tu, err := url.Parse(raw)\n\tif err != nil || u.Scheme != \"https\" || u.Hostname() == \"\" || u.User != nil || u.RawQuery != \"\" || u.Fragment != \"\" || (u.Path != \"\" && u.Path != \"/\") {\n\t\treturn errors.New(\"objectstore: production endpoint must be an HTTPS origin without credentials, path, query, or fragment\")\n\t}","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/objectstore/objectstore.go#L172-L208","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nstore, err := objectstore.New(objectstore.Config{Endpoint: \"minio:9000\"})\n// after\nstore, err := objectstore.New(objectstore.Config{\n    Endpoint: \"minio:9000\",\n    Bucket:   \"caveman-artifacts\",\n})","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(cfg.Endpoint) == \"\" || strings.TrimSpace(cfg.Bucket) == \"\" {\n    return errors.New(\"endpoint and bucket must be set\")\n}","typeGuard":null,"tryCatchPattern":"store, err := objectstore.New(cfg)\nif err != nil {\n    return fmt.Errorf(\"object store config invalid: %w\", err)\n}","preventionTips":["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"],"tags":["objectstore","configuration","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}