Skip to content

Fix parser crash from tree-sitter 0.26.0's unstable Point coordinates - #9

Merged
Naseem77 merged 4 commits into
mainfrom
naseem77-fix-tree-sitter-point-coords
Aug 29, 2026
Merged

Fix parser crash from tree-sitter 0.26.0's unstable Point coordinates#9
Naseem77 merged 4 commits into
mainfrom
naseem77-fix-tree-sitter-point-coords

Conversation

@Naseem77

Copy link
Copy Markdown
Owner

Problem

graphora-kg==0.2.0 permits tree-sitter>=0.23, which allows the currently-latest tree-sitter==0.26.0. That release has a known upstream bug (already fixed upstream, but no corrected release is published yet): reading a node's Point via the named .row/.column attributes is unstable for source coordinates beyond the small-integer range. On real files this doesn't just return a wrong number — it can segfault the interpreter.

Graphora read node.start_point.row / node.end_point.row directly in graphora/parser.py, so any large enough source file (row > 256) hit this under 0.26.0. Axios's index.d.ts at 6ac574e0 (543 lines) is a deterministic real-world trigger, first hit near line 386.

This reproduces with a clean pip install graphora-kg, a clean main checkout, and the prior editable install alike — it's a real dependency-compatibility defect in main, not local contamination.

Fix

  • graphora/parser.py: added a _point_row() helper that reads a Point's row via index access (point[0]) instead of the named .row attribute. Tuple/index access is stable on both affected and unaffected tree-sitter versions. Replaced all 3 call sites (function ranges, call-site lines, symbol lines). No public API, confidence tagging, supported-language, or output changes.
  • pyproject.toml: excluded tree-sitter==0.26.0 (tree-sitter>=0.23,!=0.26.0) as defense-in-depth, so any other/future code path can't silently receive the broken release. The lower bound (>=0.23) and any future corrected release above 0.26.0 remain installable — no upper cap.

Regression coverage

  • tests/fixtures/large_coordinates.ts: small, locally-authored TypeScript fixture with two functions past line 256 (rows 261/265, 0-based), so the relevant coordinates fall outside the affected small-integer range.
  • tests/core/test_core_parser_large_coordinates.py: parses the fixture in an isolated subprocess, so a future dependency regression (including a segfault, as reproduced below) becomes an ordinary, isolated test failure rather than crashing the whole test run.
  • tests/core/test_core_packaging.py: asserts both the installed package metadata and pyproject.toml exclude tree-sitter==0.26.0 while keeping >=0.23 and any future corrected release installable.

Validation performed

Environment: macOS arm64, Python 3.11.6, uv for env/dependency management.

  1. Full test suite: pytest -q67 passed, 46 skipped (skips are FalkorDB-integration tests, no local server). Ran with both the resolved tree-sitter==0.25.2 and with tree-sitter==0.26.0 force-installed — both pass with the fix.
  2. Bug reproduction (before the fix): with the fix stashed and tree-sitter==0.26.0 installed, the new regression test segfaults the subprocess (returncode == -11). Restoring the fix makes it pass. This confirms the defect is real and confirms the regression test catches it.
  3. Packaging: python -m build → clean wheel + sdist, twine check dist/*PASSED for both.
  4. Wheel install verification: installed the built wheel into a fresh uv venv with resolved dependencies (tree-sitter==0.25.2 chosen automatically due to the new exclusion). Verified module provenance (graphora.parser.__file__ resolves to the installed site-packages, not the source checkout) and importlib.metadata.requires("graphora-kg") reports tree-sitter!=0.26.0,>=0.23. Re-ran the large-coordinate parse 5 times from this install — consistent, correct line numbers every time.
  5. Axios integration verification (base 65e8d1e2, head 6ac574e0, temporary clone only — no third-party source committed):
    • Indexed the full repo (139 files after default ignores) with the embedded graph store, 3 repeated runs, identical non-empty stats each time: {"files": 139, "symbols": 185, "calls": 201, "imports": 279}.
    • index.d.ts (543 lines) parsed via tree-sitter, 4 symbols extracted, max symbol line 469 (> 256, exercising the real-world trigger coordinate).
    • Repeated the same indexing 3 more times with tree-sitter==0.26.0 force-installed — identical stats, confirming the fix holds against the actual buggy dependency on the real trigger file, not just the synthetic fixture.
    • index.d.ts content is identical between the base and head commits; the base/head diff itself only touches lib/, test/, and config files, unrelated to this fix.

Limitations / scope

  • This does not add a corrected tree-sitter release — none is published yet upstream. The !=0.26.0 exclusion plus the safe-indexing fix is the mitigation until one ships.
  • No linting/type-checking step exists in this repo's CI (.github/workflows/ci.yml only runs pytest and python -m build + twine check); those are the checks that were run here.
  • Third-party (axios) source was never committed — it was cloned to a temp directory for verification only and deleted afterward.

Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com

Naseem77 and others added 4 commits August 29, 2026 14:48
tree-sitter 0.26.0 has an upstream bug (already fixed, not yet released)
where reading a node's Point via the named .row/.column attributes is
unstable for source coordinates beyond the small-integer range. On real
files (e.g. axios's index.d.ts, first triggered near line 386) this can
segfault the interpreter. Tuple/index access (point[0], point[1]) is
stable on both affected and unaffected tree-sitter versions.

Replace the three .row accesses in graphora/parser.py with a small
_point_row() helper that reads Point.row via index access. No public API,
confidence tagging, or supported-language changes.

Also exclude tree-sitter==0.26.0 in pyproject.toml as defense-in-depth so
other/future code paths can't silently receive the broken release, while
keeping >=0.23 and any future corrected release (>0.26.0) installable.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- tests/fixtures/large_coordinates.ts: a small, locally-authored
  TypeScript fixture with two functions past line 256 (rows 261 and 265),
  so relevant coordinates fall outside tree-sitter 0.26.0's affected
  small-integer range.
- test_core_parser_large_coordinates.py: parses the fixture in an
  isolated subprocess (a dependency regression - including a segfault,
  as reproduced against unpatched code under tree-sitter 0.26.0 - becomes
  an ordinary, isolated test failure) and asserts the extracted function
  and call line numbers.
- test_core_packaging.py: asserts the installed package metadata and
  pyproject.toml both exclude tree-sitter==0.26.0 while keeping >=0.23
  and any future corrected release installable.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Bump the active version surfaces from 0.2.0 to 0.2.1 for the tree-sitter
Point-coordinate compatibility fix in this PR:
- pyproject.toml: [project].version
- graphora/__init__.py: __version__ (also surfaced by `graphora --version`)

The v0.2.0 git tag and no other historical references were changed --
this only touches active release metadata.

Extend tests/core/test_core_packaging.py with
test_active_version_surfaces_agree(), which asserts __version__, the
pyproject.toml version, and the installed package metadata version all
match, so a partial version bump fails a normal test instead of shipping
inconsistently.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
README.md's banner used a repo-relative <img src="assets/banner.gif">.
GitHub resolves that against the repo, but PyPI renders the packaged long
description with no repository base, so the image never loads on the
PyPI project page. Switch to the absolute raw-asset URL:
https://raw.githubusercontent.com/Naseem77/Graphora/main/assets/banner.gif

Verified the URL responds 200 with content-type: image/gif, and that it
is the only source of this image in the packaged wheel/sdist long
description (built graphora_kg-0.2.1 wheel + sdist, inspected
dist-info/METADATA and PKG-INFO: absolute URL present, repo-relative
path absent; twine check passes on both).

Added test_readme_banner_uses_absolute_url_in_packaged_long_description
to tests/core/test_core_packaging.py to keep this from regressing.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@Naseem77
Naseem77 merged commit 584e45e into main Aug 29, 2026
4 checks passed
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.

1 participant