Skip to content

langgraph_wrapper rejects every Windows absolute path in its graph reference #2185

Description

@Shatabdi-katonic

Version

1.8.0

Which installation method(s) does this occur on?

PyPi

Describe the bug.

langgraph_wrapper validates its graph reference — the module_path:graph_name string from
the config — by counting colons before it parses it:

if config.graph.count(":") != 1:
    raise ValueError(
        f"Graph definition path '{config.graph}' must contain exactly one colon to split module and name "
        f"(e.g., '/path/to/module.py:graph_name'). Found {config.graph.count(':')}.")

module_path, name = config.graph.rsplit(":", 1)

A Windows absolute path carries a colon of its own for the drive letter, so
C:\path\to\module.py:graph has two — one from C:, one separating module from graph name —
and the guard rejects it before the split is ever reached:

ValueError: Graph definition path 'C:/Users/me/work/my_graph.py:graph' must contain exactly
one colon to split module and name (e.g., '/path/to/module.py:graph_name'). Found 2.

The guard is stricter than the parser it protects. The very next line splits with
rsplit(":", 1), which partitions on the last colon and already returns
('C:\path\to\module.py', 'graph') correctly. Nothing downstream depends on the
exactly-one-colon invariant — the check is the only thing rejecting these paths.

This happens in nat/plugins/langchain/langgraph_workflow.py::register, reached from
WorkflowBuilder.from_config. That is during workflow construction, so the failure occurs
before the workflow exists at all — it is a hard startup failure, not a degraded path, and on
Windows there is no absolute-path spelling of the reference that gets past it.

Expected: C:\path\to\module.py:graph resolves to module path C:\path\to\module.py and
graph name graph, exactly as /path/to/module.py:graph resolves on POSIX. A reference with
no colon at all, or with an empty module path or graph name, should still be rejected.

Three notes on scope:

  • POSIX absolute paths and relative paths are unaffected — they contain exactly one colon, so
    the guard holds. This is why the bug is invisible to the existing suite in
    packages/nvidia_nat_langchain/tests/test_langgraph_workflow.py: the parsing has no direct
    test at all, because it is inline in register and can only be exercised by loading a real
    graph module.
  • Relative paths still work, so the workaround is to chdir to the graph's directory and use
    my_graph.py:graph. That is fine interactively but awkward for config-driven deployments,
    where the YAML is templated and absolute paths are the norm — it makes the process working
    directory part of the deployment contract.
  • The error message reports the colon count and shows a POSIX example, with nothing pointing at
    the drive letter, so it reads as "you wrote the reference wrongly" rather than "a drive letter
    is not supported here". If the config supplied forward slashes the message renders as
    C:/Users/..., which makes the second colon even harder to spot.

str.rpartition(":") is a drop-in for the whole guard: partition on the last colon and check
that both halves are non-empty, instead of counting. Pulling that into a small
split_graph_path() helper also makes the parsing unit-testable without loading a graph
module, which is what the current inline form prevents. Happy to open a PR with that change
plus regression tests for the Windows forms.

Minimum reproducible example

"""Repro: langgraph_wrapper rejects every Windows absolute path.

The guard runs before the module is loaded, so the file need not exist.

    pip install nvidia-nat-langchain==1.8.0
"""
import asyncio

from nat.builder.workflow_builder import WorkflowBuilder
from nat.plugins.langchain.langgraph_workflow import LanggraphWrapperConfig


async def main():
    config = LanggraphWrapperConfig(graph=r"C:\work\my_graph.py:graph")
    print("rsplit gives:", config.graph.rsplit(":", 1))
    async with WorkflowBuilder() as builder:
        await builder.add_function("wf", config)


asyncio.run(main())

Relevant log output

rsplit gives: ['C:\work\my_graph.py', 'graph']
Traceback (most recent call last):
File "C:\Users\shata\Downloads\nvidia\repro_e2e.py", line 18, in
asyncio.run(main())
File "...\Lib\asyncio\runners.py", line 195, in run
return runner.run(main)
File "...\Lib\asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
File "...\Lib\asyncio\base_events.py", line 691, in run_until_complete
return future.result()
File "C:\Users\shata\Downloads\nvidia\repro_e2e.py", line 15, in main
await builder.add_function("wf", config)
File "...\site-packages\nat\builder\workflow_builder.py", line 672, in add_function
build_result = await self._build_function(name=name, config=config)
File "...\site-packages\nat\builder\workflow_builder.py", line 620, in _build_function
return await _build_function_impl(
File "...\site-packages\nat\builder\workflow_builder.py", line 255, in _build_function_impl
build_result = await exit_stack.enter_async_context(build_fn(config, inner_builder))
File "...\Lib\contextlib.py", line 659, in enter_async_context
result = await _enter(cm)
File "...\Lib\contextlib.py", line 210, in aenter
return await anext(self.gen)
File "...\site-packages\nat\plugins\langchain\langgraph_workflow.py", line 213, in register
raise ValueError(
ValueError: Graph definition path 'C:\work\my_graph.py:graph' must contain exactly one colon to split module and name (e.g., '/path/to/module.py:graph_name'). Found 2.

Other/Misc.

Relative paths are unaffected, so chdir + my_graph.py:graph is a workaround.

nvidia-nat-core 1.8.0
nvidia-nat-langchain 1.8.0
langgraph 1.2.11
langchain-core 1.6.1
python 3.12.10
OS Windows 11

Reproduced on 1.8.0 from PyPI, at langgraph_workflow.py:213. The same
count(":") != 1 guard is present unchanged on develop today.

Code of Conduct

  • I agree to follow the NeMo Agent Toolkit Code of Conduct
  • I have searched the open bugs and have found no duplicates for this bug report

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs TriageNeed team to review and classifybugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions