🔴 Required Information
Describe the Bug:
GET /apps/{app_name}/app-info returns 500 Internal Server Error for any app whose root or sub-agent defines instruction as an InstructionProvider (a callable) instead of a plain string. AgentInfo in google/adk/utils/agent_info.py types the field as instruction: str and assigns current_agent.instruction verbatim, so building the response raises an unhandled pydantic.ValidationError. Callable instructions are a documented, first-class feature (Callable[[ReadonlyContext], str | Awaitable[str]]) and the agent runs fine at runtime — only the app-info introspection endpoint crashes.
Steps to Reproduce:
- Create an agent whose instruction is a callable:
# agents/dyn/agent.py
from google.adk.agents import LlmAgent
from google.adk.agents.readonly_context import ReadonlyContext
def dynamic_instruction(ctx: ReadonlyContext) -> str:
return "You are a helpful assistant."
root_agent = LlmAgent(
name="dyn",
model="gemini-3.7-flash", # any model; never reached
description="Agent with a dynamic (callable) instruction.",
instruction=dynamic_instruction, # callable, not a str
)
- Run adk web agents
- Request curl http://localhost:8000/apps/dyn/app-info
- Receive 500 Internal Server Error (stack trace below)
Expected Behavior:
app-info should succeed for agents with callable instructions — returning a serialized AgentInfo where instruction is coerced/resolved to a string (or a readable placeholder) rather than raising.
Observed Behavior:
500, with:
File ".../google/adk/cli/api_server.py", line 1416, in get_adk_app_info
agents=await get_agents_dict(root_agent),
File ".../google/adk/utils/agent_info.py", line 71, in _traverse
agents_dict[current_agent.name] = AgentInfo(
File ".../pydantic/main.py", line 263, in __init__
validated_self = self.__pydantic_validator__.validate_python(...)
pydantic_core._pydantic_core.ValidationError: 1 validation error for AgentInfo
instruction
Input should be a valid string [type=string_type,
input_value=<function dynamic_instruction at 0x...>, input_type=function]
Environment Details:
- ADK Library Version (pip show google-adk): 2.7.1
- Desktop OS: Linux (Ubuntu, Docker container)
- Python Version (python -V): 3.11
Model Information:
- Are you using LiteLLM: N/A — model-independent; the model is never reached (validation fails while building app-info, before any inference). Reproduces regardless of provider.
- Which model is being used: N/A (any; e.g. gemini-3.7-flash)
🟡 Optional Information
Regression:
Not a regression — broken since the app-info endpoint was introduced (commit da438fafd, 2026-04-06). AgentInfo.instruction has been typed str from that first commit and is still str on main, so no released version handles callable instructions here.
Logs:
pydantic_core._pydantic_core.ValidationError: 1 validation error for AgentInfo
instruction
Input should be a valid string [type=string_type,
input_value=<function dynamic_instruction at 0x...>, input_type=function]
For further information visit https://errors.pydantic.dev/2.13/v/string_type
Screenshots / Video:
N/A
Additional Context:
Root cause in google/adk/utils/agent_info.py:
class AgentInfo(pydantic.BaseModel):
...
instruction: str # LlmAgent.instruction is Union[str, InstructionProvider]
# get_agents_dict._traverse():
agents_dict[current_agent.name] = AgentInfo(
...
instruction=current_agent.instruction, # may be a callable -> ValidationError
)
Suggested fix — coerce a callable before validation:
@pydantic.field_validator("instruction", mode="before")
@classmethod
def _coerce_callable_instruction(cls, v):
if callable(v):
return f"<InstructionProvider: {getattr(v, '__name__', repr(v))}>"
return v
(Alternatively, resolve the provider when a context is available and fall back to a placeholder — note an InstructionProvider may be async and may require session state, so eager resolution isn't always safe here.)
Distinct from the invalid-app_name 500 fixed by #5374 / #5376 / #6376 — this is a valid app whose callable instruction fails validation. Separately, get_agents_dict only traverses isinstance(sub_agent, LlmAgent), so non-LlmAgent sub-agents (e.g. RemoteA2aAgent) are silently omitted from agents/sub_agents — expected, but worth noting for anyone using app-info as an inventory.
Minimal Reproduction Code:
from google.adk.agents import LlmAgent
from google.adk.agents.readonly_context import ReadonlyContext
def dynamic_instruction(ctx: ReadonlyContext) -> str:
return "You are a helpful assistant."
root_agent = LlmAgent(
name="dyn",
model="gemini-3.7-flash",
description="Agent with a dynamic (callable) instruction.",
instruction=dynamic_instruction,
)
# adk web agents -> GET /apps/dyn/app-info -> 500
How often has this issue occurred?:
- Always (100%) — deterministic for any callable instruction.
🔴 Required Information
Describe the Bug:
GET /apps/{app_name}/app-info returns 500 Internal Server Error for any app whose root or sub-agent defines instruction as an InstructionProvider (a callable) instead of a plain string. AgentInfo in google/adk/utils/agent_info.py types the field as instruction: str and assigns current_agent.instruction verbatim, so building the response raises an unhandled pydantic.ValidationError. Callable instructions are a documented, first-class feature (Callable[[ReadonlyContext], str | Awaitable[str]]) and the agent runs fine at runtime — only the app-info introspection endpoint crashes.
Steps to Reproduce:
Expected Behavior:
app-info should succeed for agents with callable instructions — returning a serialized AgentInfo where instruction is coerced/resolved to a string (or a readable placeholder) rather than raising.
Observed Behavior:
500, with:
File ".../google/adk/cli/api_server.py", line 1416, in get_adk_app_info agents=await get_agents_dict(root_agent), File ".../google/adk/utils/agent_info.py", line 71, in _traverse agents_dict[current_agent.name] = AgentInfo( File ".../pydantic/main.py", line 263, in __init__ validated_self = self.__pydantic_validator__.validate_python(...) pydantic_core._pydantic_core.ValidationError: 1 validation error for AgentInfo instruction Input should be a valid string [type=string_type, input_value=<function dynamic_instruction at 0x...>, input_type=function]Environment Details:
Model Information:
🟡 Optional Information
Regression:
Not a regression — broken since the app-info endpoint was introduced (commit da438fafd, 2026-04-06). AgentInfo.instruction has been typed str from that first commit and is still str on main, so no released version handles callable instructions here.
Logs:
pydantic_core._pydantic_core.ValidationError: 1 validation error for AgentInfo instruction Input should be a valid string [type=string_type, input_value=<function dynamic_instruction at 0x...>, input_type=function] For further information visit https://errors.pydantic.dev/2.13/v/string_typeScreenshots / Video:
N/A
Additional Context:
Root cause in google/adk/utils/agent_info.py:
Suggested fix — coerce a callable before validation:
(Alternatively, resolve the provider when a context is available and fall back to a placeholder — note an InstructionProvider may be async and may require session state, so eager resolution isn't always safe here.)
Distinct from the invalid-app_name 500 fixed by #5374 / #5376 / #6376 — this is a valid app whose callable instruction fails validation. Separately, get_agents_dict only traverses isinstance(sub_agent, LlmAgent), so non-LlmAgent sub-agents (e.g. RemoteA2aAgent) are silently omitted from agents/sub_agents — expected, but worth noting for anyone using app-info as an inventory.
Minimal Reproduction Code:
How often has this issue occurred?: