Skip to content

Inline property map in MATCH pattern silently matches nothing — should error if unsupported #1111

Closed

Description

@junk151516

Environment: v0.9.0, Windows amd64, --mode moderate index.

Summary: Using an inline property map inside a MATCH pattern returns an empty result set with the generic "no results" hint, while the equivalent WHERE clause returns rows. If the Cypher subset doesn't support inline property maps, this should be a parse/validation error — silently returning 0 rows makes LLM agents (the main consumers of this tool) conclude the edges don't exist.

Repro

cli query_graph --project P --query "MATCH (a)-[r:CALLS]->(b {name: 'auto_match'}) RETURN a.qualified_name"
# → {"rows":[],"total":0,"hint":"Query returned no results..."}      ← silent empty

cli query_graph --project P --query "MATCH (a)-[r:CALLS]->(b) WHERE b.name = 'auto_match' RETURN a.qualified_name"
# → 2 rows (correct)

Related: RETURN type(r) also doesn't resolve (returns the row count in both columns instead of the relationship type) — same "unsupported syntax should error, not mislead" argument:

cli query_graph --project P --query "MATCH ()-[r]->() RETURN type(r) AS tipo, count(*) AS n ORDER BY n DESC"
# → {"columns":["tipo","n"],"rows":[["176178","176178"]],"total":1}

Suggested fix: either support inline property maps (they're the most common Cypher idiom LLMs emit) or reject them with an explicit error listing the supported subset.

Activity

  1. added
    cypherCypher query language parser/executor bugs
    parsing/qualityGraph extraction bugs, false positives, missing edges
    windowsWindows-specific issues
    on Jul 16, 2026
  2. added
    bugSomething isn't working
    ux/behaviorDisplay bugs, docs, adoption UX
    and removed
    windowsWindows-specific issues
    on Jul 16, 2026
  3. added this to the 0.9.1-rc milestone on Jul 16, 2026
  4. added
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Jul 16, 2026
  5. DeusData commented on Jul 16, 2026

    @DeusData
    Owner

    Thanks for the precise paired queries. This is a high-priority 0.9.1-rc correctness bug: unsupported syntax must not silently produce authoritative-looking empty or fabricated results. Please keep the inline property-map case and type(r) case as separate RED assertions because they exercise different parser/evaluator paths. The fix may implement the syntax or fail closed with a specific unsupported-syntax error, but it must not return a successful misleading result.

  6. added a commit that references this issue on Jul 31, 2026
    b43bddd
  7. junk151516 commented on Jul 31, 2026

    @junk151516
    ContributorAuthor

    Confirming the inline-property-map half on the released RC, not just on HEAD — and reporting that the original repro in this issue was conflating two separate defects.

    Environment: v0.9.1-rc.1, Windows amd64, ui variant, --mode moderate, indexed into an isolated CBM_CACHE_DIR. Corpus: a real Python/TypeScript repo, 13,475 nodes / 49,261 edges.

    The inline map works now

    Target with 81 callers (ground truth from RETURN b.name AS n, count(*) AS c, which groups correctly):

    query rows
    MATCH (a:Function)-[r:CALLS]->(b:Function {name:'set_schema'}) RETURN a.qualified_name 81
    MATCH (a:Function)-[r:CALLS]->(b:Function) WHERE b.name='set_schema' RETURN a.qualified_name 81
    MATCH (a)-[r:CALLS]->(b {name:'set_schema'}) RETURN a.qualified_name — the shape reported here 81
    MATCH (a)-[r:CALLS]->(b) WHERE b.name='set_schema' RETURN a.qualified_name 81

    So closing this half is justified. Two follow-ups.

    The v0.9.0 repro had no label on the source node — the #1196 shape

    That is very likely why the two halves behaved as one back then. On this build the mechanisms separate cleanly: inline maps resolve, and what remains is #1196's scan-budget truncation, still reproducing on the RC. Same repo, target with 1,140 callers:

    truth (source labeled, no --max-rows):            1140
    
    source UNLABELED:   --max-rows 100   ->     0
                        --max-rows 500   ->     0
                        --max-rows 1000  ->   760     <- plausible, and wrong
                        --max-rows 2000  ->  1140
                        --max-rows 4000  ->  1140
    
    source labeled:     --max-rows 100   ->   100     <- limits output, as intended
                        --max-rows 1000  ->  1000
    

    Why this matters for the acceptance criteria of this issue: the 81-caller target above passes in all four forms because its candidate population fits inside the default budget. A regression test for inline property maps built on a small fixture will therefore pass whether or not inline maps work at all. To be a genuine RED assertion it needs either a target whose candidate population exceeds max_rows, or a labeled source node so #1196 cannot mask the outcome.

    Request

    The inline-map case is confirmed working, but it landed without an assertion — b43bddd adds only the two type(r) tests, and the commit message closes this half as not reproducing. Given the contract stated above in this thread (unsupported or unresolved syntax must not return a successful misleading result), could an assertion be added for it, or the case tracked wherever that contract is pinned? As it stands nothing prevents a silent regression, and silence is exactly the failure mode this issue was opened about.

    type(r), for anyone arriving here from the RC

    Still broken on v0.9.1-rc.1, since b43bddd merged after the RC was cut: MATCH (a)-[r]->(b) RETURN type(r) AS t, count(*) AS n ORDER BY n DESC returns a single row whose both columns read 49261 — the total edge count.

    The #1358 workaround holds on this build: MATCH (a)-[r]->(b) WITH type(r) AS t RETURN t, count(*) AS c ORDER BY c DESC → 25 correct rows (DEFINES 13691, CALLS 13030, USAGE 8737, …).

    Worth noting the workaround is narrower than it looks: moving the aggregate into the WITH (WITH type(r) AS t, count(*) AS n RETURN t, n) still fabricates the single 49261/49261 row. That path appears to be covered by the with_agg_* call sites in the merge, so it should be fixed too — but it is worth its own assertion, since users reaching for the workaround are one keystroke away from the same wrong answer.

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.ux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions