Skip to content

fix: _parse_path fails to navigate a lone top-level bracket index - #236

Merged
tstadel merged 3 commits into
deepset-ai:mainfrom
mittalpk:fix/parse-path-lone-bracket-index
Aug 7, 2026
Merged

tstadel merged 3 commits into
deepset-ai:mainfrom
mittalpk:fix/parse-path-lone-bracket-index

Conversation

@mittalpk

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes RichExplorer._parse_path() in src/deepset_mcp/tokonomics/explorer.py: when a navigation path has exactly one component, it returned the raw part (parts[0]) instead of wrapping it in glom.Path. That's fine when the lone part is a string attribute name (glom accepts bare strings as specs), but breaks when it's an int bracket index — glom does not accept a raw int as a spec, so glom(obj, 0) raises a TypeError wrapped in GlomError, which _get_object_at_path reports as Object 'X' does not have a value at path '[0]' — even though index 0 clearly exists.

This affects every object-store tool that takes a path parameter (get_from_object_store, get_slice_from_object_store, grep_object_store, sed_object_store, yq_object_store): whenever an LLM tries to index the first/Nth item of a top-level list result — a very natural first navigation move — it gets a false "not found" error instead of the value.

Bonus fix, same root cause: an empty bracket pair (path="[]") previously raised an uncaught IndexError (not GlomError) directly out of _parse_path, since _get_object_at_path's try/except GlomError only wraps the glom() call itself, not the _parse_path() call that builds the spec. Fixed by the same change.

Fix

Always use Path(*parts). glom.Path already handles a single part correctly (string or int) and zero parts (returns the object unchanged) — the special-casing was unnecessary and the source of both bugs.

How was this tested?

  • Reproduced both bugs directly against unpatched main with a standalone script using InMemoryBackend/ObjectStore/RichExplorer (no live deepset Cloud credentials needed):
    store = ObjectStore(backend=InMemoryBackend(), ttl=0)
    obj_id = store.put(["first", "second", "third"])
    RichExplorer(store).explore(obj_id=obj_id, path="[0]")
    # ValueError: Object 'obj_001' does not have a value at path '[0]'.
  • Added 3 new tests to test/unit/tokonomics/test_explorer.py: test_parse_path_lone_bracket_index, test_explore_lone_bracket_index_on_list, test_parse_path_empty_brackets. Confirmed all 3 fail against unpatched explorer.py (git stash) with the exact IndexError/ValueError described above, and pass after the fix.
  • Updated test_parse_path_simple, which previously asserted _parse_path("attr") == "attr" (a bare string) — that assertion encoded the old, inconsistent contract. Updated it to assert the now-uniform Path return type and verify it still navigates correctly via glom.
  • uv run --dev pytest -m "not integration" — 803 passed, 4 skipped (pre-existing, unrelated), no regressions.
  • make lint / make format-check — clean.
  • make types (mypy) — clean, 146 source files.

Notes for the reviewer

Small, behavior-preserving fix — no change for existing multi-part paths (already used Path(*parts)); only the previously-broken single-part case changes, from a crash/false-negative to correct navigation.

mittalpk and others added 2 commits July 31, 2026 18:11
_parse_path special-cased a single-part path by returning the raw part
(parts[0]) instead of wrapping it in glom.Path when there was only one
path component. This works fine when that lone part is a string
attribute name (glom accepts bare strings as specs), but breaks when
it's an int bracket index: glom does not accept a raw int as a spec,
so glom(obj, 0) raises a TypeError wrapped in GlomError, which
_get_object_at_path then reports as a misleading "Object 'X' does not
have a value at path '[0]'" -- even though index 0 clearly exists.

This affects every object-store tool that takes a path parameter
(get_from_object_store, get_slice_from_object_store, grep_object_store,
sed_object_store, yq_object_store): any time an LLM tries to index the
first/Nth item of a top-level list result -- the most natural first
navigation move -- it gets a false "not found" error.

Fixed by always using Path(*parts), which glom.Path already handles
correctly for a single part (whether string or int) and for zero parts
(returns the object unchanged, fixing a related uncaught IndexError on
an empty bracket pair like "[]" that the old parts[0] access could hit
-- _parse_path's own call site only catches glom.GlomError, not
exceptions raised while building the path spec itself).
@tstadel

tstadel commented Aug 7, 2026

Copy link
Copy Markdown
Member

@mittalpk thank you for the fix!

@tstadel
tstadel merged commit 65f0f2d into deepset-ai:main Aug 7, 2026
6 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.

2 participants