{"record":{"id":"970276fd0e904237","repo":"BerriAI/litellm","slug":"bucket-name-must-be-provided-for-gcs-destination","errorCode":null,"errorMessage":"bucket_name must be provided for GCS destination","messagePattern":"bucket_name must be provided for GCS destination","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/integrations/focus/destinations/gcs_destination.py","lineNumber":29,"sourceCode":"    encode_gcs_object_name_for_url,\n)\n\nfrom .base import FocusDestination, FocusTimeWindow\n\n\nclass FocusGCSDestination(GCSBucketBase, FocusDestination):\n    \"\"\"Upload serialized Focus exports to GCS using the GCS JSON API.\"\"\"\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 GCS destination\")\n        super().__init__(bucket_name=bucket_name)\n        service_account_json: Final = config.get(\"service_account_json\")\n        if service_account_json is not None:\n            self.path_service_account_json = service_account_json\n        self.prefix = prefix.rstrip(\"/\")\n\n    async def deliver(\n        self,\n        *,\n        content: bytes,\n        time_window: FocusTimeWindow,\n        filename: str,\n    ) -> None:\n        object_name: Final = self._build_object_key(time_window=time_window, filename=filename)\n        headers: Final = await self.construct_request_headers(service_account_json=self.path_service_account_json)\n        headers[\"Content-Type\"] = \"application/octet-stream\"\n        encoded_name: Final = encode_gcs_object_name_for_url(object_name)\n        url: Final = (","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/focus/destinations/gcs_destination.py#L11-L47","documentation":"FocusGCSDestination's constructor reads bucket_name from its config dict and immediately raises if falsy before calling super().__init__ on GCSBucketBase. This is the destination-class-level guard; it normally fires only when the class is instantiated directly, bypassing the factory (the factory already enforces FOCUS_GCS_BUCKET_NAME).","triggerScenarios":"Instantiating FocusGCSDestination(prefix=..., config={...}) directly with config missing 'bucket_name' or config=None; passing bucket under a different key like 'bucket' or 'gs://bucket' as a full URI instead of a bare name.","commonSituations":"Custom wiring that constructs the destination class instead of going through the factory; config dicts assembled from YAML where the key name drifted; passing the full gs:// URI rather than the bare bucket name.","solutions":["Include bucket_name (bare bucket name, no gs:// scheme) in the config dict passed to FocusGCSDestination.","Prefer using the destination factory, which also resolves env vars, instead of constructing the class directly.","Validate the config dict keys before instantiation."],"exampleFix":"# before\ndest = FocusGCSDestination(prefix=\"focus\", config={\"bucket\": \"my-bucket\"})\n\n# after\ndest = FocusGCSDestination(prefix=\"focus\", config={\"bucket_name\": \"my-bucket\"})","handlingStrategy":"validation","validationCode":"cfg = config or {}\nif not cfg.get(\"bucket_name\"):\n    raise ValueError(\"FocusGCSDestination requires config['bucket_name'] (bare name, no gs:// scheme)\")","typeGuard":"def is_valid_gcs_dest_config(config: dict | None) -> bool:\n    return bool(config) and isinstance(config.get(\"bucket_name\"), str) and bool(config[\"bucket_name\"].strip()) and not config[\"bucket_name\"].startswith(\"gs://\")","tryCatchPattern":"try:\n    dest = FocusGCSDestination(prefix=prefix, config=config)\nexcept ValueError as e:\n    if \"bucket_name\" in str(e):\n        raise ConfigError(\"GCS destination misconfigured\") from e\n    raise","preventionTips":["Prefer the destination factory over direct construction so env fallbacks apply.","Keep a config schema (pydantic/JSON schema) for destination dicts to catch key-name drift early."],"tags":["focus","gcs","configuration","validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}