BerriAI/litellm · error · ValueError
bucket_name must be provided for GCS destination
Error message
bucket_name must be provided for GCS destination
What it means
FocusGCSDestination.__init__ raises this ValueError when the resolved config dict has no truthy 'bucket_name' key. The destination uploads serialized FOCUS billing exports to Google Cloud Storage, so a target bucket is mandatory; the check fails fast at construction instead of at first upload. Note that when the destination is built through FocusDestinationFactory, the factory raises its own 'FOCUS_GCS_BUCKET_NAME must be provided for GCS exports' first, so this exact message fires when FocusGCSDestination is instantiated directly.
Solutions
- Pass bucket_name in the destination config: FocusGCSDestination(prefix='focus', config={'bucket_name': 'my-bucket', 'service_account_json': '/path/to/sa.json'})
- Or set export FOCUS_GCS_BUCKET_NAME=my-bucket and construct via FocusDestinationFactory.create(provider='gcs', prefix='focus')
- Verify the bucket name is exact: no gs:// prefix, no trailing slash, correct project (gcloud storage buckets list)
- Also pass service_account_json (or FOCUS_GCS_PATH_SERVICE_ACCOUNT) if you do not rely on Application Default Credentials
Example fix
# before
FocusGCSDestination(prefix='focus', config={'bucket': 'litellm-focus'})
# after
FocusGCSDestination(prefix='focus', config={'bucket_name': 'litellm-focus'}) Defensive patterns
Strategy: validation
Validate before calling
import os
bucket = (destination_config or {}).get("bucket_name") or os.getenv("FOCUS_GCS_BUCKET_NAME")
if not bucket:
raise SystemExit("Set FOCUS_GCS_BUCKET_NAME or destination_config['bucket_name'] before enabling the GCS FOCUS destination") Type guard
from typing import Any
import os
def has_valid_gcs_bucket(config: dict[str, Any] | None) -> bool:
"""True when a non-empty GCS bucket is resolvable from config or env."""
return bool((config or {}).get("bucket_name") or os.getenv("FOCUS_GCS_BUCKET_NAME")) Try / catch
try:
destination = FocusGCSDestination(prefix="focus", config=cfg)
except ValueError as e:
if "bucket_name" in str(e):
raise SystemExit(f"FOCUS GCS destination misconfigured: {e}") from e
raise Prevention
- Fail fast at process start: validate FOCUS_GCS_BUCKET_NAME (or config['bucket_name']) before the export scheduler ever runs
- Add the env var to deployment manifests and a config-lint step in CI
- Use bare bucket names (no gs:// prefix) everywhere
When it happens
Trigger: Calling FocusGCSDestination(prefix=..., config=...) with config=None, {}, or a dict where 'bucket_name' is missing, empty string, or None. Via the normal path, setting neither destination_config['bucket_name'] nor the FOCUS_GCS_BUCKET_NAME env var causes the factory's equivalent error before this line is reached.
Common situations: FOCUS_GCS_BUCKET_NAME not set in the deployment env, a typo'd config key (e.g. 'bucket' or 'gs://my-bucket' under a different key), YAML/env config where None-valued keys were filtered out before reaching the constructor, or direct instantiation in tests without a config.
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
- model param not passed in.
- BFL error
- Cisco AI Defense guardrail: invalid rule definition
- Configuration validation failed
- Custom code guardrail requires a guardrail_name
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/970276fd0e904237.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/integrations/focus/destinations/gcs_destination.py:29
encode_gcs_object_name_for_url,
)
from .base import FocusDestination, FocusTimeWindow
class FocusGCSDestination(GCSBucketBase, FocusDestination):
"""Upload serialized Focus exports to GCS using the GCS JSON API."""
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 GCS destination")
super().__init__(bucket_name=bucket_name)
service_account_json: Final = config.get("service_account_json")
if service_account_json is not None:
self.path_service_account_json = service_account_json
self.prefix = prefix.rstrip("/")
async def deliver(
self,
*,
content: bytes,
time_window: FocusTimeWindow,
filename: str,
) -> None:
object_name: Final = self._build_object_key(time_window=time_window, filename=filename)
headers: Final = await self.construct_request_headers(service_account_json=self.path_service_account_json)
headers["Content-Type"] = "application/octet-stream"
encoded_name: Final = encode_gcs_object_name_for_url(object_name)
url: Final = (View on GitHub (pinned to 77b7c6c40c)