-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
🔴 Required Information
Please ensure all items in this section are completed to allow for efficient
triaging. Requests without complete information may be rejected / deprioritized.
If an item is not applicable to you - please mark it as N/A
Describe the Bug:
Implemented a root Adk Agent that uses a OpenAPIToolset() which points to a local OpenAPI server backend. For the testing I use Okta as Oauth provider.
The initial Okta sign-in works but then when it has an error on Adk agent in a secondary call that says
"ERROR - oauth2_credential_exchanger.py:208 - Failed to exchange authorization code: invalid_request: Cannot supply multiple client credentials. Use one of the following: credentials in the Authorization header, credentials in the post body, or a client_assertion in the post body."
Steps to Reproduce:
Please provide a numbered list of steps to reproduce the behavior:
- Install '...'
- Run '....'
- Open '....'
- Provide error or stacktrace
Expected Behavior:
A clear and concise description of what you expected to happen.
Observed Behavior:
What actually happened? Include error messages or crash stack traces here.
Environment Details:
- ADK Library Version (pip show google-adk):
- Desktop OS:** [e.g., macOS, Linux, Windows]
- Python Version (python -V):
Model Information:
- Are you using LiteLLM: Yes/No
- Which model is being used: (e.g., gemini-2.5-pro)
🟡 Optional Information
Providing this information greatly speeds up the resolution process.
Regression:
Did this work in a previous version of ADK? If so, which one?
Logs:
Please attach relevant logs. Wrap them in code blocks (```) or attach a
text file.
2026-03-16 11:25:34,597 - INFO - envs.py:83 - Loaded .env file for agent at /Users/daxiao/code/openapi-agent/adk_agents/.env
2026-03-16 11:25:34,599 - INFO - envs.py:83 - Loaded .env file for agent at /Users/daxiao/code/openapi-agent/adk_agents/.env
2026-03-16 11:25:34,902 - INFO - _client.py:1025 - HTTP Request: GET https://integrator-4489750.okta.com/oauth2/default/.well-known/openid-configuration "HTTP/1.1 200 OK"
2026-03-16 11:25:34,924 - INFO - openapi_toolset.py:231 - Parsed tool: root_get
2026-03-16 11:25:34,924 - INFO - openapi_toolset.py:231 - Parsed tool: get_details_current_time_get
2026-03-16 11:25:34,926 - INFO - agent_loader.py:130 - Found root_agent in agent.agent
INFO: ::1:60495 - "POST /run_sse HTTP/1.1" 200 OK
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/flows/llm_flows/base_llm_flow.py:148: UserWarning: [EXPERIMENTAL] CredentialManager: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
credential = await CredentialManager(auth_config).get_auth_credential(
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/auth/credential_manager.py:84: UserWarning: [EXPERIMENTAL] CredentialExchangerRegistry: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
self._exchanger_registry = CredentialExchangerRegistry()
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/auth/credential_manager.py:85: UserWarning: [EXPERIMENTAL] CredentialRefresherRegistry: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
self._refresher_registry = CredentialRefresherRegistry()
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/auth/credential_manager.py:86: UserWarning: [EXPERIMENTAL] OAuth2DiscoveryManager: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
self._discovery_manager = OAuth2DiscoveryManager()
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/auth/credential_manager.py:92: UserWarning: [EXPERIMENTAL] OAuth2CredentialExchanger: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
oauth2_exchanger = OAuth2CredentialExchanger()
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/utils/feature_decorator.py:88: UserWarning: [EXPERIMENTAL] BaseCredentialExchanger: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
return orig_init(self, *args, **kwargs)
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/auth/credential_manager.py:106: UserWarning: [EXPERIMENTAL] OAuth2CredentialRefresher: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
oauth2_refresher = OAuth2CredentialRefresher()
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/utils/feature_decorator.py:88: UserWarning: [EXPERIMENTAL] BaseCredentialRefresher: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
return orig_init(self, *args, **kwargs)
INFO: ::1:60495 - "GET /debug/trace/session/8028abab-3804-452d-a6f5-7d356ff8e1f7 HTTP/1.1" 200 OK
INFO: ::1:60495 - "GET /dev-ui/?code=adQsOghKTOmc4W1slwl4xZ9x3DmtxErKFZB_dTn13FA&state=jq78YL6vvDzVNWAKjub3zp2qVCZ80a HTTP/1.1" 200 OK
INFO: ::1:60495 - "GET /dev-ui/assets/config/runtime-config.json HTTP/1.1" 304 Not Modified
INFO: ::1:60495 - "POST /run_sse HTTP/1.1" 200 OK
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/auth/auth_handler.py:50: UserWarning: [EXPERIMENTAL] OAuth2CredentialExchanger: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
exchanger = OAuth2CredentialExchanger()
/Users/daxiao/code/openapi-agent/.venv/lib/python3.14/site-packages/google/adk/auth/exchanger/oauth2_credential_exchanger.py:188: UserWarning: [EXPERIMENTAL] create_oauth2_session: This feature is experimental and may change or be removed in future versions without notice. It may introduce breaking changes at any time.
client, token_endpoint = create_oauth2_session(auth_scheme, auth_credential)
2026-03-16 11:25:36,207 - ERROR - oauth2_credential_exchanger.py:208 - Failed to exchange authorization code: invalid_request: Cannot supply multiple client credentials. Use one of the following: credentials in the Authorization header, credentials in the post body, or a client_assertion in the post body.
2026-03-16 11:25:36,331 - ERROR - oauth2_credential_exchanger.py:208 - Failed to exchange authorization code: invalid_request: Cannot supply multiple client credentials. Use one of the following: credentials in the Authorization header, credentials in the post body, or a client_assertion in the post body.
2026-03-16 11:25:36,335 - INFO - types.py:2570 -
Note: Conversion of fields that are not included in the JSONSchema class are ignored.
Json Schema is now supported natively by both Vertex AI and Gemini API. Users
are recommended to pass/receive Json Schema directly to/from the API. For example:
1. the counter part of GenerateContentConfig.response_schema is
GenerateContentConfig.response_json_schema, which accepts [JSON
Schema](https://json-schema.org/)
2. the counter part of FunctionDeclaration.parameters is
FunctionDeclaration.parameters_json_schema, which accepts [JSON
Schema](https://json-schema.org/)
3. the counter part of FunctionDeclaration.response is
FunctionDeclaration.response_json_schema, which accepts [JSON
Schema](https://json-schema.org/)
2026-03-16 11:25:36,340 - WARNING - _api_client.py:105 - Both GOOGLE_API_KEY and GEMINI_API_KEY are set. Using GOOGLE_API_KEY.
2026-03-16 11:25:36,360 - INFO - google_llm.py:185 - Sending out request, model: gemini-3-flash-preview, backend: GoogleLLMVariant.GEMINI_API, stream: False
2026-03-16 11:25:38,117 - INFO - _client.py:1740 - HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-3-flash-preview:generateContent "HTTP/1.1 200 OK"
2026-03-16 11:25:38,121 - INFO - google_llm.py:250 - Response received from the model.
Screenshots / Video:
If applicable, add screenshots or screen recordings to help explain
your problem.
Additional Context:
Add any other context about the problem here.
agent.py
import logging
import os
from google.adk.tools.openapi_tool.auth.auth_helpers import openid_url_to_scheme_credential
from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset
from google.adk.agents.llm_agent import Agent
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
credential_dict = {
"client_id": os.environ.get('OAUTH_CLIENT_ID'),
"client_secret": os.environ.get('OAUTH_CLIENT_SECRET'),
}
auth_scheme, auth_credential = openid_url_to_scheme_credential(
openid_url=os.environ.get('OIDC_CONFIG_URL'),
credential_dict=credential_dict,
scopes=['agent:time','openid','offline_access'],
)
# Open API spec
file_path = "./agent/openapi.yaml"
file_content = None
try:
with open(file_path, "r") as file:
file_content = file.read()
except FileNotFoundError:
# so that the execution does not continue when the file is not found.
raise FileNotFoundError(f"Error: The API Spec '{file_path}' was not found.")
# Example with a YAML string
openapi_spec_yaml = file_content
time_toolset = OpenAPIToolset(
spec_str=openapi_spec_yaml,
spec_str_type="yaml",
auth_scheme=auth_scheme,
auth_credential=auth_credential,
)
root_agent = Agent(
model='gemini-3-flash-preview',
name='openapi_time_agent',
description=
"An agent that can get the current time in various cities using the get_time_agent.",
instruction=
("You are a helpful assistant that can retrieve the current time in various cities. "
"To get the current time in a city, use the tools 'time_toolset'."
),
tools=[time_toolset], # Pass the toolset
)openapi.yaml
openapi: 3.0.0
info:
title: Remote Time API
version: 1.0.0
servers:
- url: http://127.0.0.1:8081
paths:
/:
get:
summary: Root
operationId: root__get
responses:
"200":
description: Successful Response
content:
application/json:
schema: {}
/current_time:
get:
summary: Get Details
operationId: get_details_current_time_get
security:
- BearerAuth: []
parameters:
- name: city
in: query
required: false
schema:
anyOf:
- type: string
- type: "null"
title: City
responses:
"200":
description: Successful Response
content:
application/json:
schema: {}
"422":
description: Validation Error
content:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
components:
schemas:
HTTPValidationError:
properties:
detail:
items:
$ref: "#/components/schemas/ValidationError"
type: array
title: Detail
type: object
title: HTTPValidationError
ValidationError:
properties:
loc:
items:
anyOf:
- type: string
- type: integer
type: array
title: Location
msg:
type: string
title: Message
type:
type: string
title: Error Type
input:
title: Input
ctx:
type: object
title: Context
type: object
required:
- loc
- msg
- type
title: ValidationError
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: CustomAuthTokenMinimal Reproduction Code:
Please provide a code snippet or a link to a Gist/repo that isolates the issue.
// Code snippet hereHow often has this issue occurred?:
- Always (100%)
- Often (50%+)
- Intermittently (<50%)
- Once / Rare