fix(sdk): pass [] instead of None for allowed/disallowed tools (NoneType crash) - #206
Merged
RichardAtCT merged 1 commit intoSep 11, 2026
Conversation
When DISABLE_TOOL_VALIDATION=true, ClaudeSDKManager was passing None for allowed_tools and disallowed_tools. The downstream claude-agent-sdk (versions 0.1.x through at least 0.2.82) calls `list(self._options.allowed_tools)` unconditionally in `subprocess_cli.py:_apply_skills_defaults` and crashes with "TypeError: 'NoneType' object is not iterable" before the CLI process even starts. Symptom: every Telegram message produces "Claude integration failed". This patches the symptom in Cct by passing empty lists. The CLI treats an empty list the same as "no --allowedTools flag" → no restriction, which is the intent of DISABLE_TOOL_VALIDATION=true. Filed upstream as well: https://github.com/anthropics/claude-agent-sdk-python (pending). Repro: set DISABLE_TOOL_VALIDATION=true + ENABLE_MCP=true in .env, send any message. SDK never returns past ClaudeSDKClient.connect(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Sep 11, 2026
RichardAtCT
pushed a commit
that referenced
this pull request
Sep 11, 2026
Integration fixes for the six PRs merged into this branch. Each change belongs to a specific PR that could not land as-is: #196 — removed an unused `patch` import from the new webhook test (flake8 F401 would have failed CI on main). #177, #178 — reformatted with black; both were submitted unformatted. #206 — dropped the .gitignore hunk, which added the contributor's personal .env.bak/.env.bak2/.env.kai entries (the trailing-newline fix on config/mcp.json is kept). Rewrote the rationale comment: the claimed "'NoneType' object is not iterable" crash does not reproduce on the pinned claude-agent-sdk 0.1.39, which guards with a truthiness check. The change is still worth taking — ClaudeAgentOptions declares these as list[str] with default_factory=list, so None violates the dataclass contract and the project floats on ^0.1.39 — but as hardening rather than as the crash fix it claimed to be. Added explicit Optional[List[str]] annotations so mypy does not infer list[Any] from the [] branch. #206 x #220 — reconciled the escape-hatch assertion in test_disable_tool_validation_restores_permissive_behavior, which #220 added asserting `allowed_tools is None`. Both values are falsy, so the CLI omits --allowedTools either way and DISABLE_TOOL_VALIDATION=true remains unrestricted; only the sentinel changes. Verification: 559 passed; black, isort and flake8 clean. mypy gains 3 errors, all from #196's use of self.app in webhook mode — the same Optional-narrowing pattern that already produces ten identical errors in that file, and mypy is not run in CI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tk9xKUdrarDX5KmUuwcjN8
RichardAtCT
pushed a commit
that referenced
this pull request
Sep 11, 2026
Patch release covering the security fix in #220 and the six bug fixes merged via #223 (#214, #212, #196, #177, #178, #206). Carries an upgrade note: #220 means tool calls targeting paths outside APPROVED_DIRECTORY are now denied where they previously succeeded. That restores the documented behaviour, but it is a real change for any deployment that relied on the gap. Also records the known limitation tracked in #221 — CLAUDE_ALLOWED_TOOLS does not block tools left off the list. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tk9xKUdrarDX5KmUuwcjN8
RichardAtCT
pushed a commit
that referenced
this pull request
Sep 11, 2026
Drop the out-of-scope rows for PRs merged in 1.6.2 (#214, #212, #196, #177, #178, #206), note #220, point the AskUserQuestion and ExitPlanMode items at the GUARDED_TOOLS set that 1.6.2 introduced, and remove the docs/tools.md item that 1.6.2 already fixed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LaezV767Pguhpat9zVyEs
RichardAtCT
added a commit
that referenced
this pull request
Sep 11, 2026
* docs: add v2 roadmap Plan the 2.0 release in docs/ROADMAP-v2.md: SDK 0.2 migration, interactive question/plan/permission UX over inline keyboards, file-checkpoint undo, per-conversation concurrency, a session browser, token-based usage reporting, classic-mode removal, and container/PyPI distribution. Work already covered by open pull requests is listed as out of scope so contributors do not duplicate it. Link it from the docs index and changelog. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LaezV767Pguhpat9zVyEs * chore: add community health files and first-pass review automation Add the files a contributor-driven project needs that were missing: issue forms (bug, feature, question) that ask for version, mode and logs up front; a pull request template with a hand-testing section; CODEOWNERS; MAINTAINERS.md with roles, a one-week response promise, the label set, and the path to maintainership; and a Contributor Covenant 2.1 code of conduct. Rewrite CONTRIBUTING.md, which still described the project as mid-way through "TODO-7", to cover PR scope rules, the AI-assisted contribution policy, the current source layout, and the review flow. Add Dependabot (weekly for the Claude SDK and Telegram library, monthly grouped otherwise) and restore a Claude Code Review workflow as a read-only first-pass reviewer that also covers fork PRs. Link the new files from the README, docs index and changelog. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LaezV767Pguhpat9zVyEs * fix: point project URLs at the RichardAtCT repository The Homepage, Repository and Documentation entries in pyproject.toml referenced github.com/richardatkinson/claude-code-telegram, a handle that is not the project's. These URLs surface in `pip show` and would become the links on a PyPI listing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LaezV767Pguhpat9zVyEs * docs: rebase v2 roadmap on the 1.6.2 baseline Drop the out-of-scope rows for PRs merged in 1.6.2 (#214, #212, #196, #177, #178, #206), note #220, point the AskUserQuestion and ExitPlanMode items at the GUARDED_TOOLS set that 1.6.2 introduced, and remove the docs/tools.md item that 1.6.2 already fixed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LaezV767Pguhpat9zVyEs --------- Co-authored-by: Claude <noreply@anthropic.com>
5 tasks
RichardAtCT
pushed a commit
that referenced
this pull request
Sep 11, 2026
main is red. test_allowed_tools_none_unaffected_by_approval_filter asserts that allowed_tools is None when DISABLE_TOOL_VALIDATION is set, but 94d764d (#206) changed that value to [] so it matches the list[str] that ClaudeAgentOptions declares. #217 added the test against a base that did not yet carry #206, so neither pull request was red on its own and the failure only appeared once both were merged. The test's intent is sound: the interactive-approval filter must not disturb the tool list when validation is disabled. Only the expected value was stale, so assert [] instead. Rename the test and reword its docstring, since "none" in the name is what made the mismatch easy to miss. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LaezV767Pguhpat9zVyEs
14 tasks
RichardAtCT
added a commit
that referenced
this pull request
Sep 11, 2026
) Three follow-ups to #222, all consequences of the org move and the 1.7.0 release. main was red. test_allowed_tools_none_unaffected_by_approval_filter asserted that allowed_tools is None under DISABLE_TOOL_VALIDATION, but 94d764d (#206) had changed that value to [] to match the list[str] that ClaudeAgentOptions declares. #217 added the test against a base without #206, so neither pull request was red alone and the failure appeared only once both were on main. Two other tests in the same file already assert [], so line 689 was the outlier: the expectation is corrected and the test renamed, since "none" in its name is what hid the mismatch. Repository URLs now point at overwirehq across the README, docs, SECURITY.md, the issue templates, CONTRIBUTING.md, the packaging metadata and the star-history badge. References to @RichardAtCT as a person are left alone; that account has not moved. The v2 roadmap is rebased on reality: M0 moves from 1.7 to 1.8 since the #219 security fix took that version, #217 leaves the out-of-scope table now that it is merged, and item 0.4 names ghcr.io/overwirehq/claude-code-telegram. The Unreleased changelog entries dropped during the 1.7.0 merge into #222 are restored.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When
DISABLE_TOOL_VALIDATION=trueis set, every Telegram message producesClaude integration failedand the SDK crashes before the CLI even starts:Root cause
ClaudeSDKManager.run_command(src/claude/sdk_integration.py:314) passesNoneforsdk_allowed_tools/sdk_disallowed_toolswhendisable_tool_validationis true.Downstream,
claude-agent-sdk(verified on both 0.1.81 and the latest 0.2.82) callslist(self._options.allowed_tools)unconditionally insidesubprocess_cli.py::_apply_skills_defaults.list(None)→TypeError.This is a real bug in the SDK (no None-guard on a documented-as-optional field), but the fix here is trivial on the Cct side and unblocks every user who enables MCP with
DISABLE_TOOL_VALIDATION=true(the standard recipe for adding third-party MCP servers like MemPalace, Mem0, etc.).Fix
Pass
[]instead ofNone. The CLI treats an empty list as "no--allowedToolsflag" → no restriction, which matches the intent ofDISABLE_TOOL_VALIDATION=true.Reproduction
.env:DISABLE_TOOL_VALIDATION=true+ENABLE_MCP=true+ validMCP_CONFIG_PATHClaude integration failedon every turnVerified end-to-end with a 27-tool MemPalace MCP server (Python
mempalace-mcpbinary) onclaude-agent-sdk 0.1.81+ Cct 1.6.0.Upstream
Will file matching issue/PR upstream at anthropics/claude-agent-sdk-python so the SDK adds
or []on thelist()call. Until that lands, this Cct-side guard is the practical fix.🤖 Generated with Claude Code