Skip to content

fix(sdk): pass [] instead of None for allowed/disallowed tools (NoneType crash) - #206

Merged
RichardAtCT merged 1 commit into
overwirehq:mainfrom
Aispotlightlab:fix/none-allowed-tools-crash
Sep 11, 2026
Merged

RichardAtCT merged 1 commit into
overwirehq:mainfrom
Aispotlightlab:fix/none-allowed-tools-crash

Conversation

@Aispotlightlab

Copy link
Copy Markdown
Contributor

Problem

When DISABLE_TOOL_VALIDATION=true is set, every Telegram message produces Claude integration failed and the SDK crashes before the CLI even starts:

{"error": "'NoneType' object is not iterable", "error_type": "TypeError",
 "event": "Unexpected error in Claude SDK", "logger": "src.claude.sdk_integration"}

Root cause

ClaudeSDKManager.run_command (src/claude/sdk_integration.py:314) passes None for sdk_allowed_tools / sdk_disallowed_tools when disable_tool_validation is true.

Downstream, claude-agent-sdk (verified on both 0.1.81 and the latest 0.2.82) calls list(self._options.allowed_tools) unconditionally inside subprocess_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 of None. The CLI treats an empty list as "no --allowedTools flag" → no restriction, which matches the intent of DISABLE_TOOL_VALIDATION=true.

if self.config.disable_tool_validation:
    sdk_allowed_tools = []      # was: None
    sdk_disallowed_tools = []   # was: None

Reproduction

  1. .env: DISABLE_TOOL_VALIDATION=true + ENABLE_MCP=true + valid MCP_CONFIG_PATH
  2. Send any message to the bot
  3. Without this fix: Claude integration failed on every turn
  4. With this fix: bot responds normally; MCP tools are accessible

Verified end-to-end with a 27-tool MemPalace MCP server (Python mempalace-mcp binary) on claude-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 the list() call. Until that lands, this Cct-side guard is the practical fix.


🤖 Generated with Claude Code

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>
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
RichardAtCT merged commit c444bba into overwirehq:main Sep 11, 2026
RichardAtCT added a commit that referenced this pull request Sep 11, 2026
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>
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
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants