langchain-ai/langgraph · error · ValueError
Invalid build tool: ; must be one of
Error message
Invalid build tool: {pack}; must be one of {', '.join(_BUILD_TOOLS)} What it means
Validation in the CLI's Dockerfile generator (via _get_pip_cleanup_lines / keep_pkg_tools handling): a value in the keep_pkg_tools list is not one of the recognized build tools 'pip', 'setuptools', 'wheel' (_BUILD_TOOLS). The offending tool name and the allowed set are printed; unknown values would leave broken cleanup RUN lines in the generated image.
Solutions
- Set keep_pkg_tools to a subset of ['pip','setuptools','wheel'], e.g. keep_pkg_tools: ['pip','setuptools']
- Use a boolean (true) to keep all three tools if you need any of them at runtime
- Remove misspelled entries from the keep_pkg_tools array in langgraph.json
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at libs/cli/langgraph_cli/config.py:106 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of langchain-ai/langgraph@38031739e5 (2026-08-26).
Data as JSON: /api/errors/44c2891cf19fc5b6.
Report an issue: GitHub.
Appendix: source
Thrown at libs/cli/langgraph_cli/config.py:106
def _get_pip_cleanup_lines(
install_cmd: str,
to_uninstall: tuple[str] | None,
pip_installer: Literal["uv", "pip"],
) -> str:
commands = [
f"""# -- Ensure user deps didn't inadvertently overwrite langgraph-api
RUN mkdir -p /api/langgraph_api /api/langgraph_runtime /api/langgraph_license && \
touch /api/langgraph_api/__init__.py /api/langgraph_runtime/__init__.py /api/langgraph_license/__init__.py
RUN PYTHONDONTWRITEBYTECODE=1 {install_cmd} --no-cache-dir --no-deps -e /api
# -- End of ensuring user deps didn't inadvertently overwrite langgraph-api --
# -- Removing build deps from the final image ~<:===~~~ --"""
]
if to_uninstall:
for pack in to_uninstall:
if pack not in _BUILD_TOOLS:
raise ValueError(
f"Invalid build tool: {pack}; must be one of {', '.join(_BUILD_TOOLS)}"
)
packs_str = " ".join(sorted(to_uninstall))
commands.append(f"RUN pip uninstall -y {packs_str}")
# Ensure the directories are removed entirely
packages_rm = " ".join(
f"/usr/local/lib/python*/site-packages/{pack}*" for pack in to_uninstall
)
if "pip" in to_uninstall:
packages_rm += ' && find /usr/local/bin -name "pip*" -delete || true'
commands.append(f"RUN rm -rf {packages_rm}")
wolfi_packages_rm = " ".join(
f"/usr/lib/python*/site-packages/{pack}*" for pack in to_uninstall
)
if "pip" in to_uninstall:
wolfi_packages_rm += ' && find /usr/bin -name "pip*" -delete || true'
commands.append(f"RUN rm -rf {wolfi_packages_rm}")
if pip_installer == "uv":View on GitHub (pinned to 38031739e5)