From 2d38d0ad962e4dacb261bd11657c7e02bd168797 Mon Sep 17 00:00:00 2001 From: Hugo Durand Date: Fri, 18 Sep 2026 15:11:39 -0400 Subject: [PATCH] fix(cli): validate --tag before any control plane call --- libs/cli/langgraph_cli/deploy.py | 8 +++++--- libs/cli/tests/unit_tests/cli/test_deploy_command.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libs/cli/langgraph_cli/deploy.py b/libs/cli/langgraph_cli/deploy.py index 09d77d4bf..a3adbe4d6 100644 --- a/libs/cli/langgraph_cli/deploy.py +++ b/libs/cli/langgraph_cli/deploy.py @@ -415,7 +415,7 @@ def normalize_image_tag(value: str) -> str: Tags may only contain [A-Za-z0-9_.-]. Defaults to "latest" when empty. """ if not value: - value = "latest" + value = _DEFAULT_IMAGE_TAG if not re.fullmatch(r"[A-Za-z0-9_.-]+", value): raise click.UsageError( "Image tag may only contain characters A-Z, a-z, 0-9, '_', '-', '.'" @@ -1123,7 +1123,7 @@ def _run_local_build( remote_image = str( ImageReference( f"{normalized_registry}/{normalize_name(repo_seed)}", - normalize_image_tag(tag), + tag, ) ) registry_host = normalized_registry.split("/")[0] @@ -1507,7 +1507,9 @@ def _select_source( ) if not use_remote_build: return ManagedRegistrySource( - prebuilt_image=image, image_name=image_name, tag=tag or _DEFAULT_IMAGE_TAG + prebuilt_image=image, + image_name=image_name, + tag=normalize_image_tag(tag or _DEFAULT_IMAGE_TAG), ) if remote_build_flag is None and local_build_error: em = _get_emitter() diff --git a/libs/cli/tests/unit_tests/cli/test_deploy_command.py b/libs/cli/tests/unit_tests/cli/test_deploy_command.py index 4d0790f0f..fd9817633 100644 --- a/libs/cli/tests/unit_tests/cli/test_deploy_command.py +++ b/libs/cli/tests/unit_tests/cli/test_deploy_command.py @@ -642,3 +642,13 @@ def test_push_to_with_deployment_id_fetches_the_deployment_once( "docker inspect-digest", _patch("dep-ext"), ] + + +def test_invalid_tag_fails_before_any_control_plane_call( + deploy_project: DeployProject, +) -> None: + result = deploy_project.run("--no-remote", "--tag", "not a tag") + + assert result.exit_code != 0 + assert "Image tag may only contain" in result.output + assert deploy_project.timeline == []