If you switched from ClaudeAgentOptions to AgentDefinition in the Claude Agent SDK, you may see TypeError: __init__() got an unexpected keyword argument 'disallowed_tools'. The root cause is a naming convention mismatch. AgentDefinition uses camelCase field names while ClaudeAgentOptions uses Python’s standard snake_case. Here is the complete migration table plus working examples.
Why AgentDefinition uses camelCase
The Claude Agent SDK ships in Python, TypeScript, and Node.js. Anthropic chose to keep AgentDefinition field names identical across all three languages so agent config can be shared as JSON. That means Python developers writing disallowed_tools, allowed_tools, or max_thinking_tokens hit a TypeError at construction time because the field is spelled disallowedTools in every language.
ClaudeAgentOptions on the other hand is Python-native and follows PEP 8 snake_case. Do not confuse the two.
The fix: use camelCase for AgentDefinition fields
from claude_agent_sdk import AgentDefinition, ClaudeAgentOptions
# WRONG (raises TypeError: unexpected keyword argument)
# agent = AgentDefinition(
# name="researcher",
# disallowed_tools=["shell"], # snake_case does not work here
# allowed_tools=["read", "write"],
# max_thinking_tokens=16000,
# )
# CORRECT (camelCase for AgentDefinition)
agent = AgentDefinition(
name="researcher",
description="Research and summarize papers",
disallowedTools=["shell"],
allowedTools=["read", "write", "grep"],
maxThinkingTokens=16000,
)
# Also CORRECT (snake_case for ClaudeAgentOptions)
options = ClaudeAgentOptions(
model="claude-opus-4-8",
max_tokens=32000,
disallowed_tools=["shell"], # snake_case works here
allowed_tools=["read", "write"],
)Migration table: snake_case to camelCase
| Python-style (WRONG for AgentDefinition) | Correct camelCase |
|---|---|
allowed_tools | allowedTools |
disallowed_tools | disallowedTools |
max_thinking_tokens | maxThinkingTokens |
system_prompt | systemPrompt |
additional_directories | additionalDirectories |
tool_permissions | toolPermissions |
Debugging checklist
- Confirm you are on Claude Agent SDK 0.15+ from 2026. Older versions accepted both cases, newer ones enforce camelCase strictly.
- If your linter or IDE flags
disallowedToolsas a naming convention violation, add a per-project override for the Agent SDK config namespace. Do not rename the field. - If you load agent definitions from JSON or YAML, verify the file uses camelCase keys. Copying from a Python-native config format is the top source of this TypeError.
- If you subclass AgentDefinition to add a helper, keep the parent field names as-is even if your subclass uses snake_case.
Real-world example: multi-agent researcher
from claude_agent_sdk import (
ClaudeAgentOptions,
AgentDefinition,
ClaudeSDKClient
)
# Define specialized agents using camelCase
researcher = AgentDefinition(
name="researcher",
description="Search papers and extract findings",
allowedTools=["web_search", "read"],
disallowedTools=["shell", "write"],
maxThinkingTokens=32000,
systemPrompt="You are a research assistant. Cite every claim."
)
writer = AgentDefinition(
name="writer",
description="Draft summary from research notes",
allowedTools=["read", "write"],
disallowedTools=["shell", "web_search"],
maxThinkingTokens=8000,
systemPrompt="You are an editor. Write short, clear paragraphs."
)
# ClaudeAgentOptions uses snake_case
options = ClaudeAgentOptions(
model="claude-opus-4-8",
max_tokens=32000,
agents=[researcher, writer],
)
# Both snake_case (options) and camelCase (agents) work together
client = ClaudeSDKClient(options=options)Debugging checklist for the Anthropic SDK error
Before diving into fixes, run through this diagnostic checklist. Nine times out of ten the answer surfaces here.
- Read the full traceback, not just the error message. The stack trace shows exactly which line and which call chain triggered the error. The last line names the immediate cause; earlier lines show how you got there.
- Add print or debug statements just before the failing line. Print the variable, its type, and its value. Nine out of ten error surprises come from the value being different from what you assumed.
- Check Python version compatibility. Errors sometimes result from APIs that changed between versions. Run your interpreter version check and compare against the library documentation for that version.
- Isolate the failing call in a minimal reproducer. Copy the failing line into a small standalone script with hardcoded inputs. If it fails there too, the bug is in your code. If not, something in your surrounding context is contributing.
- Search the exact error message. Include the class name and the specific text in your search. Chances are someone else hit the same issue and the fix is documented on Stack Overflow or the library’s GitHub issues.
Common causes for the Anthropic SDK error
Most instances of this error trace back to one of these root causes:
- Uninitialized or missing input. A variable was not populated before use, or the input source (file, API response, database row) did not contain the expected key or value.
- Type mismatch. The code expected a specific type (dict, list, string) but received something different. Python’s dynamic typing means this often surfaces at runtime, not at compile time.
- Version drift. The library API changed and your code assumes the old signature. Check the library’s changelog for breaking changes since the version you last used.
- Race condition or ordering issue. Async or concurrent code sometimes tries to access data before it is ready. Add awaits, locks, or explicit ordering to fix.
- Copy-paste from stale tutorial. Older tutorials may use APIs that no longer exist. Always check the official docs for the current version.
Testing and prevention
Preventing this class of error from recurring is more valuable than fixing it once. Build these habits into your workflow:
- Write tests that trigger the error path. If your test suite hits the error scenario, catch and assert it. A well-written test prevents the same bug from returning.
- Validate inputs at API boundaries. When data enters your code from external sources (HTTP requests, file uploads, database queries), validate structure and types immediately.
- Use type hints and static analysis. Tools like mypy for Python or TypeScript for JavaScript catch many type mismatches before you run the code.
- Log important state. Structured logging with context helps you debug production issues faster. Include enough context to reconstruct what happened.
- Read the library changelog. Before upgrading a dependency, skim the changelog for breaking changes. Two minutes of reading saves an hour of debugging.
When to ask for help
Some errors are worth solving yourself for the learning. Others are worth asking about early. Ask for help when: the error blocks a customer-facing feature, you have spent an hour without progress, the error involves security or data integrity, or you are unsure whether your fix will introduce new bugs. Post to Stack Overflow with a minimal reproducer, or ask a senior developer on your team. Time boxes are your friend.
Production hardening for the Anthropic SDK error
Fixing the Anthropic SDK error once is not enough. To prevent it from recurring in production, harden the surrounding code with these patterns.
- Defensive coding at API boundaries. Every function that receives external data (HTTP requests, database rows, file uploads, third-party API responses) should validate structure and types before proceeding. Use validation libraries like Pydantic (Python specific) to enforce schemas at the boundary.
- Structured logging with context. When the Anthropic SDK error occurs, your logs should include enough context to reconstruct the failure. Include the operation name, input values, user or request ID, and the full stack trace. Avoid logging sensitive data (passwords, tokens, PII).
- Error monitoring and alerting. Tools like Sentry, Rollbar, or Datadog capture production errors with stack traces and context. Set up alerts for the Anthropic SDK error so you know within minutes when it happens in production.
- Retry logic with exponential backoff. For transient errors (network failures, temporary API errors), retry with 1-second, 2-second, 4-second delays. Cap at 3-5 retries to prevent infinite loops.
- Circuit breakers for external dependencies. If an external service repeatedly fails, stop calling it for a period and return a fallback response. Prevents cascading failures.
Testing strategies to catch the Anthropic SDK error early
Investing in tests that specifically trigger the error path prevents regressions. Build these into your test suite:
- Unit tests for the failing function. Write a test that reproduces the exact conditions that caused the Anthropic SDK error. If your test fails, your fix works. If your test passes with the buggy code, your test is not testing the right thing.
- Property-based testing. Tools like Hypothesis for Python generate random inputs and check invariants hold. Great for catching edge cases you did not think of.
- Integration tests with real dependencies. Mock-heavy unit tests miss real-world issues. Have at least one integration test that hits a real database, API, or file system.
- Continuous integration. Run your test suite on every pull request. Catch bugs before they reach main.
Official documentation
Frequently Asked Questions
Why does AgentDefinition use camelCase in a Python SDK?
Anthropic ships the Agent SDK in Python, TypeScript, and Node.js with a shared JSON config schema. camelCase keeps agent definitions portable across all three runtimes without renaming.
Can I write a wrapper that accepts snake_case?
Yes. Write a small adapter that converts snake_case kwargs to camelCase before calling AgentDefinition(). This is a common pattern in Python codebases that also expose ClaudeAgentOptions to users.
Does ClaudeAgentOptions also use camelCase?
No. ClaudeAgentOptions follows Python’s PEP 8 snake_case. Only AgentDefinition and its nested types use camelCase.
Will Anthropic add snake_case aliases later?
The SDK changelog does not commit to adding snake_case aliases. Treat AgentDefinition’s camelCase as intentional API design and adapt your code accordingly.
How do I load AgentDefinition from YAML?
Save the YAML with camelCase keys, load with yaml.safe_load(), then pass with AgentDefinition(**data). Skip Python-native config libraries that auto-convert to snake_case.
