{"record":{"id":"8dbd3420e405e61f","repo":"BerriAI/litellm","slug":"bucket-name-must-be-provided-for-s3-destination","errorCode":null,"errorMessage":"bucket_name must be provided for S3 destination","messagePattern":"bucket_name must be provided for S3 destination","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/integrations/focus/destinations/s3_destination.py","lineNumber":26,"sourceCode":"\nimport boto3\n\nfrom .base import FocusDestination, FocusTimeWindow\n\n\nclass FocusS3Destination(FocusDestination):\n    \"\"\"Handles uploading serialized exports to S3 buckets.\"\"\"\n\n    def __init__(\n        self,\n        *,\n        prefix: str,\n        config: dict[str, Any] | None = None,\n    ) -> None:\n        config = config or {}\n        bucket_name: Final = config.get(\"bucket_name\")\n        if not bucket_name:\n            raise ValueError(\"bucket_name must be provided for S3 destination\")\n        self.bucket_name = bucket_name\n        self.prefix = prefix.rstrip(\"/\")\n        self.config = config\n\n    async def deliver(\n        self,\n        *,\n        content: bytes,\n        time_window: FocusTimeWindow,\n        filename: str,\n    ) -> None:\n        object_key: Final = self._build_object_key(time_window=time_window, filename=filename)\n        await asyncio.to_thread(self._upload, content, object_key)\n\n    def _build_object_key(self, *, time_window: FocusTimeWindow, filename: str) -> str:\n        start_utc: Final = time_window.start_time.astimezone(timezone.utc)\n        date_component: Final = f\"date={start_utc.strftime('%Y-%m-%d')}\"\n        parts: Final = [self.prefix, date_component]","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/focus/destinations/s3_destination.py#L8-L44","documentation":"FocusS3Destination.__init__ raises ValueError when the destination config dict has no non-empty 'bucket_name' key. The S3 destination needs a target bucket to construct object keys for FOCUS exports; without it the destination cannot be constructed safely.","triggerScenarios":"Constructing FocusS3Destination(prefix=..., config={}) or config={'bucket_name': ''} / {'bucket_name': None} — e.g. the FOCUS destination_config from env/settings omitted bucket_name.","commonSituations":"Typo in the config key ('bucket' vs 'bucket_name'); passing the settings dict of a different destination type; reading bucket from an env var that is unset.","solutions":["Pass bucket_name in the destination config: config={'bucket_name': 'my-focus-export-bucket', ...}.","Check for typos/whitespace in the key and ensure the value is a non-empty string.","Verify the bucket exists and the credentials in the same config have s3:PutObject rights."],"exampleFix":"// before\nFocusS3Destination(prefix=\"focus\", config={\"bucket\": \"my-bucket\"})\n\n// after\nFocusS3Destination(prefix=\"focus\", config={\"bucket_name\": \"my-bucket\"})","handlingStrategy":"validation","validationCode":"cfg = dest_config or {}\nif not cfg.get(\"bucket_name\"):\n    raise ValueError(\"destination_config['bucket_name'] is required for the S3 FOCUS destination\")\ndest = FocusS3Destination(prefix=prefix, config=cfg)","typeGuard":"def is_valid_s3_config(cfg: dict) -> bool:\n    return isinstance(cfg, dict) and isinstance(cfg.get(\"bucket_name\"), str) and len(cfg[\"bucket_name\"].strip()) > 0","tryCatchPattern":null,"preventionTips":["Validate destination_config against a schema (e.g. pydantic) at proxy startup.","Use one config loader for all FOCUS destinations so required keys are checked once.","Add integration tests that construct each destination with minimal valid config."],"tags":["config","s3","focus-export","validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}