{"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/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/integrations/focus/destinations/s3_destination.py#L8-L44","documentation":"FocusS3Destination.__init__ raises this ValueError when the destination config dict for a FOCUS billing-data export has no falsy 'bucket_name' key. The S3 destination is normally built by the destination factory, which resolves bucket_name from overrides or the FOCUS_S3_BUCKET_NAME environment variable before constructing the class. So seeing this exact message usually means the class was instantiated directly (or via a config path) without that resolution happening.","triggerScenarios":"Constructing FocusS3Destination(prefix=..., config={'bucket_name': ''}) or config with no bucket_name key; instantiating the class directly instead of going through the factory when FOCUS_S3_BUCKET_NAME is unset; passing a destination_config dict from YAML that omits bucket_name.","commonSituations":"Enabling FOCUS exports to S3 in litellm proxy config while forgetting the bucket setting; typos in the env var name (e.g. S3_BUCKET_NAME instead of FOCUS_S3_BUCKET_NAME); empty string values from templated config files; local dev where the env var is only set in production.","solutions":["Set the environment variable FOCUS_S3_BUCKET_NAME to the target bucket (the factory reads it automatically).","Pass bucket_name in the destination config overrides, e.g. destination_config={'bucket_name': 'my-focus-export-bucket'}, or the equivalent YAML field for S3 FOCUS exports.","If constructing FocusS3Destination yourself, always include config['bucket_name'] and fail fast with your own clearer error before calling the constructor.","Verify the value is a non-empty string — empty string is falsy and still triggers the error."],"exampleFix":"# before\nFocusS3Destination(prefix='focus/exports', config={'region': 'us-east-1'})\n\n# after\nFocusS3Destination(\n    prefix='focus/exports',\n    config={'bucket_name': 'my-focus-export-bucket', 'region': 'us-east-1'},\n)","handlingStrategy":"validation","validationCode":"import os\n\nbucket = overrides.get('bucket_name') or os.getenv('FOCUS_S3_BUCKET_NAME')\nif not bucket:\n    raise SystemExit('FOCUS_S3_BUCKET_NAME (or bucket_name override) is required before starting FOCUS exports')","typeGuard":"def has_s3_bucket(config: dict) -> bool:\n    return bool(config.get('bucket_name') or os.getenv('FOCUS_S3_BUCKET_NAME'))","tryCatchPattern":"try:\n    dest = FocusS3Destination(prefix=prefix, config=config)\nexcept ValueError as e:\n    if 'bucket_name' in str(e):\n        raise ConfigError('Set FOCUS_S3_BUCKET_NAME before enabling S3 FOCUS exports') from e\n    raise","preventionTips":["Put FOCUS_S3_BUCKET_NAME in the deployment manifest checklist alongside other required secrets.","Fail at config-load time with a clear message instead of letting the constructor raise mid-startup.","Use the destination factory rather than instantiating FocusS3Destination directly."],"tags":["s3","focus-export","configuration","constructor-validation"],"backgroundTag":"missing-required-config","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}