[DOCS] Python SDK Code Example for "Permissions Fallback" Raises Runtime ValueError

Resolved 💬 4 comments Opened Jan 21, 2026 by coygeek Closed Feb 27, 2026

Documentation Type

Unclear/confusing documentation

Documentation Location

https://platform.claude.com/docs/en/agent-sdk/permissions#permissions-fallback-for-unsandboxed-commands

Section/Topic

The Python code example in the section "Permissions Fallback for Unsandboxed Commands".

Current Documentation

The current Python example uses a string for the prompt argument while simultaneously defining a can_use_tool callback:

async def main():
    async for message in query(
        prompt="Deploy my application",  # <--- String prompt
        options=ClaudeAgentOptions(
            sandbox={
                "enabled": True,
                "allowUnsandboxedCommands": True
            },
            permission_mode="default",
            can_use_tool=can_use_tool    # <--- Callback provided
        )
    ):
        print(message)

What's Wrong or Missing?

This code will crash immediately upon execution.

The Python SDK implementation enforces a requirement that if a can_use_tool callback is provided, the prompt must be an AsyncIterable, not a str.

Passing a string prompt with a tool callback raises the following ValueError in src/claude_agent_sdk/_internal/client.py:

"can_use_tool callback requires streaming mode. Please provide prompt as an AsyncIterable instead of a string."

The documentation example creates a configuration that the SDK explicitly validates against and rejects.

Suggested Improvement

Update the Python example to wrap the prompt in an async generator/iterable so that it is compatible with the can_use_tool callback.

Suggested corrected code:

from claude_agent_sdk import query, ClaudeAgentOptions

# Define a simple async prompt generator
async def prompt_stream():
    yield {
        "type": "user", 
        "message": {"role": "user", "content": "Deploy my application"}
    }

async def can_use_tool(tool: str, input: dict) -> bool:
    # Check if the model is requesting to bypass the sandbox
    if tool == "Bash" and input.get("dangerouslyDisableSandbox"):
        print(f"Unsandboxed command requested: {input.get('command')}")
        # Return True to allow, False to deny
        return True # logic here
    return True

async def main():
    async for message in query(
        prompt=prompt_stream(), # Updated to use async iterable
        options=ClaudeAgentOptions(
            sandbox={
                "enabled": True,
                "allowUnsandboxedCommands": True
            },
            permission_mode="default",
            can_use_tool=can_use_tool
        )
    ):
        print(message)

Impact

High - Prevents users from using a feature

Additional Context

This validation logic is located in src/claude_agent_sdk/_internal/client.py (lines 40-45 in the source provided):

if options.can_use_tool:
    # canUseTool callback requires streaming mode (AsyncIterable prompt)
    if isinstance(prompt, str):
        raise ValueError(
            "can_use_tool callback requires streaming mode. "
            "Please provide prompt as an AsyncIterable instead of a string."
        )

Other sections of the documentation (such as "Handle approvals and user input") correctly use prompt_stream() patterns, but this specific section reverts to using a string string, causing the error.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗