{"record":{"id":"153040a7b26fe47f","repo":"BerriAI/litellm","slug":"both-project-id-and-topic-id-must-be-provided","errorCode":null,"errorMessage":"Both project_id and topic_id must be provided","messagePattern":"Both project_id and topic_id must be provided","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/integrations/gcs_pubsub/pub_sub.py","lineNumber":58,"sourceCode":"        Initialize Google Cloud Pub/Sub publisher\n\n        Args:\n            project_id (str): Google Cloud project ID\n            topic_id (str): Pub/Sub topic ID\n            credentials_path (str, optional): Path to Google Cloud credentials JSON file\n        \"\"\"\n        from litellm.proxy.utils import _premium_user_check\n\n        _premium_user_check()\n\n        self.async_httpx_client = get_async_httpx_client(llm_provider=httpxSpecialProvider.LoggingCallback)\n\n        self.project_id = project_id or os.getenv(\"GCS_PUBSUB_PROJECT_ID\")\n        self.topic_id = topic_id or os.getenv(\"GCS_PUBSUB_TOPIC_ID\")\n        self.path_service_account_json = credentials_path or os.getenv(\"GCS_PATH_SERVICE_ACCOUNT\")\n\n        if not self.project_id or not self.topic_id:\n            raise ValueError(\"Both project_id and topic_id must be provided\")\n\n        self.flush_lock = asyncio.Lock()\n        super().__init__(**kwargs, flush_lock=self.flush_lock)\n        asyncio.create_task(self.periodic_flush())\n        self.log_queue: list[SpendLogsPayload | StandardLoggingPayload] = []\n\n    async def construct_request_headers(self) -> dict[str, str]:\n        \"\"\"Construct authorization headers using Vertex AI auth\"\"\"\n        from litellm import vertex_chat_completion\n\n        (\n            _auth_header,\n            vertex_project,\n        ) = await vertex_chat_completion._ensure_access_token_async(\n            credentials=self.path_service_account_json,\n            project_id=self.project_id,\n            custom_llm_provider=\"vertex_ai\",\n        )","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/integrations/gcs_pubsub/pub_sub.py#L40-L76","documentation":"Pubsub.py raises ValueError when, after fallbacks, either project_id or topic_id is unresolved. The constructor accepts explicit project_id/topic_id arguments, falling back to GCS_PUBSUB_PROJECT_ID and GCS_PUBSUB_TOPIC_ID env vars; both must end up non-None. Note a premium-user check runs just before this, so enterprise licensing must already be in order.","triggerScenarios":"Registering the GCS Pub/Sub callback with neither constructor args nor GCS_PUBSUB_PROJECT_ID/GCS_PUBSUB_TOPIC_ID set; setting only one of the two env vars; typo'd variable names in the deployment manifest.","commonSituations":"Enabling pubsub logging from docs that show only one variable; k8s secret mounted with the wrong key names; splitting project/topic across different config mechanisms and one not loading.","solutions":["Set both env vars: GCS_PUBSUB_PROJECT_ID and GCS_PUBSUB_TOPIC_ID.","Or pass project_id= and topic_id= explicitly when constructing the Pubsub callback.","Verify with printenv in the actual runtime environment.","Remember GCS_PATH_SERVICE_ACCOUNT is optional only if default vertex auth works; project/topic are never optional."],"exampleFix":"# before\n# only GCS_PUBSUB_TOPIC_ID set\n\n# after\nexport GCS_PUBSUB_PROJECT_ID=my-gcp-project\nexport GCS_PUBSUB_TOPIC_ID=litellm-logs","handlingStrategy":"validation","validationCode":"import os\n\nproject = project_id or os.getenv('GCS_PUBSUB_PROJECT_ID')\ntopic = topic_id or os.getenv('GCS_PUBSUB_TOPIC_ID')\nif not project or not topic:\n    raise SystemExit('Both GCS_PUBSUB_PROJECT_ID and GCS_PUBSUB_TOPIC_ID (or constructor args) are required')","typeGuard":"def pubsub_resolved(project_id: str | None, topic_id: str | None) -> bool:\n    return bool(project_id or os.getenv('GCS_PUBSUB_PROJECT_ID')) and bool(topic_id or os.getenv('GCS_PUBSUB_TOPIC_ID'))","tryCatchPattern":"try:\n    Pubsub(project_id=project, topic_id=topic)\nexcept ValueError as e:\n    if 'project_id and topic_id' in str(e):\n        raise ConfigError('Set GCS_PUBSUB_PROJECT_ID and GCS_PUBSUB_TOPIC_ID') from e\n    raise","preventionTips":["Set both GCS_PUBSUB_* env vars in the same manifest block so one is never missing.","Note the premium check runs first — license the proxy before adding this callback."],"tags":["pubsub","gcp","logging-callback","configuration"],"backgroundTag":"missing-required-config","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}