Skip to content

/apps/{app_name}/app-info returns 500 when an agent's instruction is an InstructionProvider (callable) instead of a str #6909

Closed

Description

@itaieban

🔴 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:

  1. 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
    )
  2. Run adk web agents
  3. Request curl http://localhost:8000/apps/dyn/app-info
  4. 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.

Activity

  1. a2105z commented on Aug 26, 2026

    @a2105z
    Contributor

    I'll take this.

    GET /apps/{app_name}/app-info should not 500 when instruction is an InstructionProvider. I'll coerce callables to a readable placeholder in AgentInfo rather than resolving them (providers can be async and need session state).

  2. added
    agent config[Component] This issue is related to the Agent Config interface and implementation
    on Aug 27, 2026
  3. surajksharma07 commented on Aug 27, 2026

    @surajksharma07
    Collaborator

    @itaieban Reproduced the exact same ValidationError on our end at agent_info.py:71. The placeholder-coercion approach in #6913 looks like the right call since it avoids invoking the provider (which could be async or need session state).

    Could you pull that branch and confirm app-info comes back clean for your callable-instruction agents before it gets merged?
    Just want to make sure it's solid on your end too before this moves further through review.

  4. added a commit that references this issue on Sep 1, 2026
    ada8652
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

agent config[Component] This issue is related to the Agent Config interface and implementationrequest clarification[Status] The maintainer need clarification or more information from the author

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions