BerriAI/litellm · error · ValueError
bucket_name must be provided for S3 destination
Error message
bucket_name must be provided for S3 destination
What it means
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.
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.
Example fix
# before
FocusS3Destination(prefix='focus/exports', config={'region': 'us-east-1'})
# after
FocusS3Destination(
prefix='focus/exports',
config={'bucket_name': 'my-focus-export-bucket', 'region': 'us-east-1'},
) Defensive patterns
Strategy: validation
Validate before calling
import os
bucket = overrides.get('bucket_name') or os.getenv('FOCUS_S3_BUCKET_NAME')
if not bucket:
raise SystemExit('FOCUS_S3_BUCKET_NAME (or bucket_name override) is required before starting FOCUS exports') Type guard
def has_s3_bucket(config: dict) -> bool:
return bool(config.get('bucket_name') or os.getenv('FOCUS_S3_BUCKET_NAME')) Try / catch
try:
dest = FocusS3Destination(prefix=prefix, config=config)
except ValueError as e:
if 'bucket_name' in str(e):
raise ConfigError('Set FOCUS_S3_BUCKET_NAME before enabling S3 FOCUS exports') from e
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- api_base is required
- api_key must be provided for Vantage destination (set…
- integration_token must be provided for Vantage destination…
- MAVVRIK_FOCUS_FREQUENCY=
- S3 bucket name is required. Set 's3_bucket_name' parameter…
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/8dbd3420e405e61f.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/integrations/focus/destinations/s3_destination.py:26
import boto3
from .base import FocusDestination, FocusTimeWindow
class FocusS3Destination(FocusDestination):
"""Handles uploading serialized exports to S3 buckets."""
def __init__(
self,
*,
prefix: str,
config: dict[str, Any] | None = None,
) -> None:
config = config or {}
bucket_name: Final = config.get("bucket_name")
if not bucket_name:
raise ValueError("bucket_name must be provided for S3 destination")
self.bucket_name = bucket_name
self.prefix = prefix.rstrip("/")
self.config = config
async def deliver(
self,
*,
content: bytes,
time_window: FocusTimeWindow,
filename: str,
) -> None:
object_key: Final = self._build_object_key(time_window=time_window, filename=filename)
await asyncio.to_thread(self._upload, content, object_key)
def _build_object_key(self, *, time_window: FocusTimeWindow, filename: str) -> str:
start_utc: Final = time_window.start_time.astimezone(timezone.utc)
date_component: Final = f"date={start_utc.strftime('%Y-%m-%d')}"
parts: Final = [self.prefix, date_component]View on GitHub (pinned to 77b7c6c40c)