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
Version
1.8.0
Which installation method(s) does this occur on?
PyPi
Describe the bug.
langgraph_wrappervalidates itsgraphreference — themodule_path:graph_namestring fromthe config — by counting colons before it parses it:
A Windows absolute path carries a colon of its own for the drive letter, so
C:\path\to\module.py:graphhas two — one fromC:, one separating module from graph name —and the guard rejects it before the split is ever reached:
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 theexactly-one-colon invariant — the check is the only thing rejecting these paths.
This happens in
nat/plugins/langchain/langgraph_workflow.py::register, reached fromWorkflowBuilder.from_config. That is during workflow construction, so the failure occursbefore 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:graphresolves to module pathC:\path\to\module.pyandgraph name
graph, exactly as/path/to/module.py:graphresolves on POSIX. A reference withno colon at all, or with an empty module path or graph name, should still be rejected.
Three notes on scope:
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 directtest at all, because it is inline in
registerand can only be exercised by loading a realgraph module.
chdirto the graph's directory and usemy_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 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 checkthat 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 graphmodule, 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
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:graphis 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(":") != 1guard is present unchanged ondeveloptoday.Code of Conduct