fix(ast_parser): parse_structure has no exception handling around parser/handler — crashes dir loop on malformed input #82

Open
opened 2026-04-18 20:23:55 -06:00 by claude-code · 0 comments
Collaborator

Problem

parse_structure() wraps the file read in try/except OSError, but the tree-sitter parse and the language handler are unprotected:

luminos_lib/ast_parser.py:306-314:

try:
    with open(path, "rb") as f:
        source = f.read()
except OSError as e:
    return f"Error reading file: {e}"

tree = parser.parse(source)                 # ← can raise
result = handler(tree.root_node, source)    # ← can raise
return json.dumps(result, indent=2)

The caller _tool_parse_structure (ai.py:286-292) doesn't wrap either — so any exception propagates up into _run_dir_loop and crashes the per-directory investigation.

Why this matters

  • tree-sitter can crash or misbehave on very large, binary, or malformed source
  • Language handlers assume specific node shapes — an unexpected tree (e.g., a Python file with encoding the parser misinterprets) can trip an AttributeError or IndexError inside the handler
  • The agent calls parse_structure on any file it thinks is source, including ones it hasn't verified — so the unsafe paths are reachable from the agent's normal tool use

CLAUDE.md requires "Graceful degradation everywhere … individual dir-loop failures — all handled without crashing the run." A tool that raises breaks that contract.

Fix

Wrap lines 312-313 in try/except Exception and return an error string:

try:
    tree = parser.parse(source)
    result = handler(tree.root_node, source)
except Exception as e:
    return f"Error parsing structure: {e}"
return json.dumps(result, indent=2)

A returned error string is the established pattern for every other tool in ai.py.

Acceptance

  • parse_structure never propagates an exception out to the caller
  • Malformed / very-large / non-source files return an error string rather than crashing
  • ast_parser.py stays exempt from unit tests (CLAUDE.md), but a smoke test via _tool_parse_structure in test_ai_pure.py (feeding a crafted input) is welcome
## Problem `parse_structure()` wraps the file read in `try/except OSError`, but the tree-sitter parse and the language handler are unprotected: `luminos_lib/ast_parser.py:306-314`: ```python try: with open(path, "rb") as f: source = f.read() except OSError as e: return f"Error reading file: {e}" tree = parser.parse(source) # ← can raise result = handler(tree.root_node, source) # ← can raise return json.dumps(result, indent=2) ``` The caller `_tool_parse_structure` (`ai.py:286-292`) doesn't wrap either — so any exception propagates up into `_run_dir_loop` and crashes the per-directory investigation. ## Why this matters - tree-sitter can crash or misbehave on very large, binary, or malformed source - Language handlers assume specific node shapes — an unexpected tree (e.g., a Python file with encoding the parser misinterprets) can trip an AttributeError or IndexError inside the handler - The agent calls `parse_structure` on any file it thinks is source, including ones it hasn't verified — so the unsafe paths are reachable from the agent's normal tool use CLAUDE.md requires "Graceful degradation everywhere … individual dir-loop failures — all handled without crashing the run." A tool that raises breaks that contract. ## Fix Wrap lines 312-313 in try/except Exception and return an error string: ```python try: tree = parser.parse(source) result = handler(tree.root_node, source) except Exception as e: return f"Error parsing structure: {e}" return json.dumps(result, indent=2) ``` A returned error string is the established pattern for every other tool in `ai.py`. ## Acceptance - [ ] `parse_structure` never propagates an exception out to the caller - [ ] Malformed / very-large / non-source files return an error string rather than crashing - [ ] `ast_parser.py` stays exempt from unit tests (CLAUDE.md), but a smoke test via `_tool_parse_structure` in `test_ai_pure.py` (feeding a crafted input) is welcome
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: archeious/luminos#82
No description provided.