Skip to content

trace_path silently accepts invalid direction values and returns empty results #480

Closed

Description

@mattiagggg

Summary

trace_path returns an empty result for every function/method I tried — callers or callees, plain or fully-qualified name, any depth — even though the underlying CALLS edges exist and are traversable via query_graph. The tool only ever echoes back {"function":...,"direction":...} with no paths/nodes.

This makes the headline call-graph traversal tool effectively non-functional in v0.8.1, at least on macOS arm64.

Environment

  • Version: codebase-memory-mcp 0.8.1
  • Platform: Darwin arm64 (macOS)
  • Repo indexed: large polyglot repo (Python 569 files, Go 190, TS 20, …) → 15,915 nodes / 67,668 edges, status:"indexed". Index reports 15,945 CALLS edges.

Repro

Index any multi-language repo, then:

$ codebase-memory-mcp cli trace_path '{"project":"<proj>","function_name":"read_file_status","direction":"callers","depth":1}'
{"function":"read_file_status","direction":"callers"}

Empty — no paths. But the edges clearly exist:

$ codebase-memory-mcp cli query_graph '{"project":"<proj>","query":"MATCH (a)-[:CALLS]->(b:Function) RETURN b.name, count(a) AS callers ORDER BY callers DESC LIMIT 8"}'
{"columns":["b.name","callers"],"rows":[["get",380],["info",374],["main",169],["load",112],["read_file_status",88],["save_files_from_dict",87],["WithTimeout",72],["keys",63]]}

read_file_status is a Function node with 88 incoming CALLS edges, yet trace_path finds nothing.

What I ruled out

  • Not a label issue. Tried both Method nodes (create) and Function nodes (read_file_status, save_files_from_dict, main, run_cmd) — all empty.
  • Not direction. callers and callees both empty.
  • Not name resolution. Bare name and fully-qualified (agentsv2.base_agent.BaseAgent.create) both empty.
  • Not missing data. The exact CALLS edges traverse fine via query_graph, so the graph is populated correctly — only the trace_path start-node lookup (or its traversal) appears to fail.

Expected

trace_path should return the caller/callee paths for read_file_status (88 callers exist), matching what query_graph can already walk.

Workaround

Use query_graph with a Cypher MATCH ... -[:CALLS*]-> ... instead; the graph data itself is correct.

Activity

  1. halindrome commented on Jun 17, 2026

    @halindrome
    Contributor

    Confirming this is a real bug — reproduced independently on a separate repo and on a build from current main (not just v0.8.1), also macOS arm64.

    A Perl project indexed with the same tree shows three refreshProperties definitions each with inbound CALLS edges via query_graph:

    query_graph  MATCH (a)-[:CALLS]->(b:Function) WHERE b.name='refreshProperties' ...
    → Corvex.Assets.refreshProperties    8 callers
      Corvex.Objects.refreshProperties   6 callers
      Corvex.Questions.refreshProperties 5 callers
    

    …but trace_path returns empty for the same functions, with both the bare and fully-qualified name:

    trace_path {"function_name":"refreshProperties","direction":"callers","depth":1}
    → {"function":"refreshProperties","direction":"callers"}
    
    trace_path {"function_name":"<proj>.apps.rest-api.lib.Corvex.Assets.refreshProperties","direction":"callers","depth":1}
    → {"function":"<proj>...refreshProperties","direction":"callers"}
    

    So the response carries no paths/nodes key at all — matching the report. The graph data is correct and walkable via Cypher (MATCH ... -[:CALLS]-> ...), so this is isolated to trace_path's own start-node lookup/traversal, not edge creation or name resolution. The query_graph Cypher workaround in the issue holds up.

  2. DeusData commented on Jun 18, 2026

    @DeusData
    Owner

    Thanks for the careful report, @mattiagggg 🙏 The split you found is the key clue: the edges traverse fine via query_graph, but trace_path returns nothing, so the graph data is correct and this is a start node lookup or traversal bug inside trace_path itself, not extraction. The fact that bare and fully qualified names both come back empty points at the name to node resolution step.

    This may be related to the name resolution work in #466, and we're checking whether that path covers trace_path's lookup too. One thing that would help narrow it: does trace_path return anything for a symbol whose name is globally unique in your repo (no overloads or duplicates)? If unique names work but ambiguous ones don't, it's the resolver; if even unique names fail, it's the traversal. This is a core tool, so it's high on our list!

  3. DeusData commented on Jun 28, 2026

    @DeusData
    Owner

    This issue now has a first-class, durable reproduction in the cumulative bug-reproduction suite landing in #667 — a test that pins the exact failing behaviour, so it's tracked and guarded against silent regression. Where #667 also lands the root-cause fix, that's called out in the PR; otherwise the reproduction makes the eventual fix straightforward and verifiable.

    The reproduction goes live once #667 merges. (Posted from the release branch's QA pass.)

  4. doug306 commented on Jun 29, 2026

    @doug306

    Corroborating on a different platform, with one extra data point that may help narrow it.

    Platform: macOS x86_64 (Intel), v0.8.1 release binary — so this isn't arm64-specific.

    Key clue: trace_path with mode:"data_flow" works, while the default mode:"calls" returns empty, on the same function and index.

    Minimal repro (2-file TS project where greet() calls helper(), and run() calls greet()):

    # The CALLS edges exist:
    cli query_graph '{"project":"P","query":"MATCH (a)-[:CALLS]->(b) RETURN a.name,b.name"}'
    # → rows: [["greet","helper"],["run","greet"]]
    
    # mode=calls — empty:
    cli trace_path '{"project":"P","function_name":"helper","direction":"callers","mode":"calls","depth":2}'
    # → {"function":"helper","direction":"callers","mode":"calls"}
    
    # mode=data_flow — correct, with hops:
    cli trace_path '{"project":"P","function_name":"greet","mode":"data_flow","depth":3}'
    # → {... "callees":[{"name":"helper","hop":1}], "callers":[{"name":"run","hop":1}]}

    Same on a large real repo: mode:"calls" is empty for an exported function with 41 inbound CALLS edges (confirmed via query_graph), but mode:"data_flow" returns 89 transitive caller entries at depth 2. Identical behavior via cli and via MCP tools/call.

    Since data_flow resolves the same bare name and traverses the same nodes/edges successfully, the name→node lookup and the edges themselves look fine — the empty result seems specific to the calls-mode traversal/serialization path, rather than name resolution.

  5. added
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Jun 30, 2026
  6. added
    awaiting-reporterWaiting on the reporter for info/repro; stale bot will warn then close
    on Jul 8, 2026
  7. github-actions commented on Jul 8, 2026

    @github-actions

    Thanks for the report! To move this forward we need a bit more so we can reproduce it ourselves:

    • the codebase-memory-mcp --version you're on
    • the exact steps or command you ran
    • a public repo (or a small dummy snippet) that shows the problem — please don't paste proprietary code

    Once that's here we'll pick it straight back up. Heads-up: issues left awaiting-reporter are automatically closed after a few weeks of silence, but a comment reopens the door anytime.

  8. DeusData commented on Jul 8, 2026

    @DeusData
    Owner

    v0.9.0 includes trace_path fixes, including same-name disambiguation and cross-edge traversal improvements. Could you retest this trace query on v0.9.0 and confirm whether it still returns empty? Marking awaiting-reporter.

  9. added this to the 0.9.1-rc milestone on Jul 8, 2026
  10. added
    parsing/qualityGraph extraction bugs, false positives, missing edges
    ux/behaviorDisplay bugs, docs, adoption UX
    and removed
    awaiting-reporterWaiting on the reporter for info/repro; stale bot will warn then close
    on Jul 16, 2026
  11. DeusData commented on Jul 16, 2026

    @DeusData
    Owner

    A current v0.9.0 Windows reproduction was reported in #1110 with the same defining behavior: exact Function and Method nodes have confirmed CALLS edges through query_graph, while trace_path returns an empty traversal for bare and fully qualified names in both directions. That closes the requested version retest gap, so I have removed awaiting-reporter and returned this canonical issue to the maintainer queue. The RED guard should preserve the existing calls-mode versus data_flow discriminator and add the v0.9.0 exact-QN case.

  12. changed the title [-]trace_path returns empty for all functions despite traversable CALLS edges (v0.8.1, macOS arm64)[/-] [+]trace_path silently accepts invalid direction values and returns empty results[/+] on Jul 22, 2026
  13. DeusData commented on Jul 22, 2026

    @DeusData
    Owner

    The v0.9.0 follow-up in #1110 identified the shared root cause: callers and callees are not accepted direction values; inbound, outbound, and both are. Valid directions return the expected graph, while arbitrary invalid strings are silently echoed in a successful empty response. I am reclassifying this canonical issue around that verified validation failure. The 0.9.1-rc acceptance case is to reject every unsupported direction explicitly and to cover the documented valid values. #1110 remains closed as the duplicate, and its separate unlabeled query_graph finding is tracked in #1196.

  14. AmirF194 commented on Sep 7, 2026

    @AmirF194
    Contributor

    This one looks resolved already. At HEAD (aa44c28) handle_trace_call_path in src/mcp/mcp.c validates direction against inbound/outbound/both and returns an explicit "invalid direction ... use inbound (callers), outbound (callees), or both" error instead of silently running with both legs false. The comment right above it even names this exact failure mode ("an unknown direction used to silently produce an empty trace... a field-eval agent burned four calls on callers/callees").

    So callers/callees now fail loudly instead of returning an empty trace, which matches the acceptance criteria from the last update here. I didn't reindex a repo and drive an end to end trace_path call, just read the validation path and confirmed it rejects the exact inputs from this issue and #1110's repro.

  15. DeusData commented on Sep 19, 2026

    @DeusData
    Owner

    Thank you for the original report and follow-up verification. Closing as fixed by c5bffb7, included in v0.11.0. Current trace_path rejects unknown directions rather than returning a misleading empty trace, and its error names inbound, outbound and both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcypherCypher query language parser/executor bugsparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.stability/performanceServer crashes, OOM, hangs, high CPU/memoryux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions