Skip to content

get_hub_nodes_tool (and 4 sibling tools) crash on every call — 'str'/'NoneType' object has no attribute 'resolve' #418

@jessmon699-netizen

Description

@jessmon699-netizen

Summary

Five MCP tools in tools/analysis_tools.py raise AttributeError on every invocation in v2.3.2. The path-resolution code passes a str/None into a function that expects pathlib.Path, and additionally assigns a tuple to a variable that's then used as a GraphStore. The combination means none of the affected tools have ever returned a result on this version.

Affected tools

  • get_hub_nodes_tool
  • get_bridge_nodes_tool
  • get_knowledge_gaps_tool
  • get_surprising_connections_tool
  • get_suggested_questions_tool

(All *_func implementations in code_review_graph/tools/analysis_tools.py.)

Reproduction

pipx install code-review-graph==2.3.2
cd /path/to/some/git/repo
code-review-graph init --platform claude-code
code-review-graph build
# Then from any MCP client:
get_hub_nodes_tool(repo_root="/path/to/some/git/repo")
# → Error calling tool 'get_hub_nodes_tool': 'str' object has no attribute 'resolve'

get_hub_nodes_tool()
# → Error calling tool 'get_hub_nodes_tool': 'NoneType' object has no attribute 'resolve'

Same crash with both repo_root provided and omitted. Other tools (get_review_context_tool, find_large_functions_tool, list_graph_stats_tool, query_graph_tool) work correctly against the same graph, so this is specific to the five listed.

Root cause

In tools/analysis_tools.py (e.g. get_hub_nodes_func, lines 17–42):

def get_hub_nodes_func(repo_root: str = "", top_n: int = 10) -> dict[str, Any]:
    root = _validate_repo_root(repo_root)   # <-- bug 1
    store = _get_store(str(root))           # <-- bug 2
    hubs = find_hub_nodes(store, top_n=top_n)

Bug 1 — wrong type to validator. _validate_repo_root in tools/_common.py:61 is typed as (path: Path) -> Path and immediately calls path.resolve(). Callers here pass a str (or None, after main._resolve_repo_root returns None), triggering AttributeError.

Bug 2 — _get_store returns a tuple. _get_store in tools/_common.py:81 was changed to return tuple[GraphStore, Path]. These five callers assign the tuple to a single name store and pass it to find_*_nodes(store: GraphStore, …) — even after fixing bug 1, the next call would fail with a different AttributeError on the tuple.

Other tools across the package follow the working pattern (store, root = _get_store(repo_root)) which suggests these five analysis_tools.py helpers were missed when the helpers' signatures were tightened.

Suggested fix

Replace the two-line setup in each of the five *_func helpers with the pattern the rest of the codebase uses:

store, _ = _get_store(repo_root)

_get_store already calls _validate_repo_root(Path(repo_root)) internally and falls back to find_project_root() when repo_root is empty/None, so the explicit pre-validation is redundant.

A regression test that calls each of the five tools against a real built graph fixture (the test could just use the package's own repo) would prevent the next reoccurrence. Right now the failure is only visible at MCP-call time.

Environment

  • code-review-graph 2.3.2 (PyPI)
  • Python 3.12.3 / Ubuntu 24.04
  • Installed via pipx install code-review-graph
  • Graph: 4521 nodes / 45651 edges / 536 files (JS + bash + Python). Other tools query it without issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions