{"record":{"id":"2f7631cebf8902a5","repo":"BerriAI/litellm","slug":"gdc-only-accepts-a-gdch-service-account-credential","errorCode":null,"errorMessage":"GDC only accepts a GDCH service account credential as a JSON api_key (expected \"type\": \"gdch_service_account\"). Other Google credential types are rejected so their token or external-account endpoints cannot drive server-side requests.","messagePattern":"GDC only accepts a GDCH service account credential as a JSON api_key \\(expected \"type\": \"gdch_service_account\"\\)\\. Other Google credential types are rejected so their token or external-account endpoints cannot drive server-side requests\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/gdc/chat/transformation.py","lineNumber":166,"sourceCode":"\n            gdch_creds: Final = self._gdch_creds_cache[cache_key]\n\n            if not getattr(gdch_creds, \"valid\", False) or not getattr(gdch_creds, \"token\", None):\n                self._fetch_auth(gdch_creds, ssl_verify)\n\n            token: Final = gdch_creds.token\n\n        return token\n\n    def _load_creds_from_key(self, api_key: str) -> tuple[Any, bool]:\n        import google.auth\n\n        try:\n            json_obj: Final = json.loads(api_key)\n        except json.JSONDecodeError:\n            return None, False\n        if not isinstance(json_obj, dict) or json_obj.get(\"type\") != self._GDCH_CREDENTIAL_TYPE:\n            raise ValueError(\n                \"GDC only accepts a GDCH service account credential as a JSON api_key \"\n                '(expected \"type\": \"gdch_service_account\"). Other Google credential types are '\n                \"rejected so their token or external-account endpoints cannot drive server-side requests.\"\n            )\n        creds, _ = google.auth.load_credentials_from_dict(json_obj)\n        return creds, True\n\n    def validate_environment(\n        self,\n        headers: dict,\n        model: str,\n        messages: list[Any],\n        optional_params: dict,\n        litellm_params: dict,\n        api_key: str | None = None,\n        api_base: str | None = None,\n    ) -> dict:\n        import google.auth.exceptions","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/gdc/chat/transformation.py#L148-L184","documentation":"The GDC (Google Distributed Cloud) transformation only accepts a service-account JSON whose top-level \"type\" is \"gdch_service_account\". _load_creds_from_key() parses the api_key as JSON and, if the type field is missing or is a different Google credential type (service_account, authorized_user, external_account, GCP ADC files), it raises this ValueError to prevent those credentials' token endpoints from being used for GDC server-side requests.","triggerScenarios":"Passing a regular GCP service-account JSON, a gcloud ADC credentials.json (type: authorized_user), or malformed JSON that parses but lacks type=gdch_service_account as the api_key for a gdc/ model.","commonSituations":"Developer reuses an existing GCP service account file because it 'looks like' the right JSON; copy-paste of application_default_credentials.json downloaded via gcloud auth application-default login; on-prem GDC install where the wrong service-account file was distributed.","solutions":["Obtain a GDCH service account JSON from the GDC console (its \"type\" is \"gdch_service_account\") and pass that file's contents as api_key.","Verify before use: python -c \"import json;print(json.load(open('key.json'))['type'])\" must print gdch_service_account.","If you intended Vertex/Gemini rather than Google Distributed Cloud, switch the model prefix (vertex_ai/ or gemini/) instead of forcing a GCP key into gdc/."],"exampleFix":"# before (wrong credential type)\napi_key = open(\"gcp_service_account.json\").read()  # \"type\": \"service_account\"\n\n# after\napi_key = open(\"gdch_service_account.json\").read()  # \"type\": \"gdch_service_account\"","handlingStrategy":"validation","validationCode":"import json\n\ndef load_gdch_key(path: str) -> str:\n    creds = json.load(open(path))\n    if creds.get(\"type\") != \"gdch_service_account\":\n        raise ValueError(\n            f\"Wrong credential type {creds.get('type')!r}; need a GDCH service account\"\n        )\n    return json.dumps(creds)","typeGuard":"def is_gdch_credential(api_key: object) -> bool:\n    if not isinstance(api_key, str):\n        return False\n    try:\n        obj = json.loads(api_key)\n    except json.JSONDecodeError:\n        return False\n    return isinstance(obj, dict) and obj.get(\"type\") == \"gdch_service_account\"","tryCatchPattern":"try:\n    litellm.completion(model=\"gdc/...\", messages=msgs, api_key=key_json)\nexcept ValueError as e:\n    if \"gdch_service_account\" in str(e):\n        raise RuntimeError(\"Supply the GDCH service account JSON, not a GCP credential\") from e\n    raise","preventionTips":["Label credential files clearly (gcp-*.json vs gdch-*.json) and never reuse ADC files for GDC.","Validate the 'type' field in deploy scripts before the key ever reaches litellm.","Remember gdc/ is Google Distributed Cloud — for Vertex or AI Studio use vertex_ai/ or gemini/ instead."],"tags":["gdc","authentication","credentials","configuration","google-cloud"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}