From 7c34168a598efdceb24fce8ce7abc7c8beb24e2d Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Fri, 27 Feb 2026 21:59:33 -0500 Subject: [PATCH 1/3] Add failing test for ActivityAlreadyStartedError wrong message ActivityAlreadyStartedError.__init__ passes "Workflow execution already started" to super().__init__(), which is a copy-paste error from WorkflowAlreadyStartedError. Add a unit test and an assertion in the existing integration test that both fail, demonstrating the bug. --- .../repro_activity_already_started_error.py | 32 +++++++++++++++++++ tests/test_activity.py | 3 ++ 2 files changed, 35 insertions(+) create mode 100644 scripts/repro_activity_already_started_error.py diff --git a/scripts/repro_activity_already_started_error.py b/scripts/repro_activity_already_started_error.py new file mode 100644 index 000000000..fb25d6b7c --- /dev/null +++ b/scripts/repro_activity_already_started_error.py @@ -0,0 +1,32 @@ +#!/usr/bin/env -S uv run --script +# +# /// script +# requires-python = ">=3.12" +# dependencies = ["temporalio"] +# /// +"""Repro: ActivityAlreadyStartedError contains wrong error message. + +The error message says "Workflow execution already started" when it should say +"Activity execution already started". + +This script demonstrates the bug without needing a Temporal server by simply +constructing the exception and printing its message. +""" + +from temporalio.exceptions import ActivityAlreadyStartedError, WorkflowAlreadyStartedError + +print("=== ActivityAlreadyStartedError message bug repro ===\n") + +wf_err = WorkflowAlreadyStartedError("wf-id", "MyWorkflow", run_id="run-1") +act_err = ActivityAlreadyStartedError("act-id", "MyActivity", run_id="run-1") + +print(f"WorkflowAlreadyStartedError message: {wf_err}") +print(f"ActivityAlreadyStartedError message: {act_err}") +print() + +if str(act_err) == str(wf_err): + print("BUG: Both errors have the same message!") + print(f" Both say: \"{act_err}\"") + print(" ActivityAlreadyStartedError should say \"Activity execution already started\"") +else: + print("OK: Error messages are distinct (bug is fixed).") diff --git a/tests/test_activity.py b/tests/test_activity.py index 0b6abaf80..0d9bfecad 100644 --- a/tests/test_activity.py +++ b/tests/test_activity.py @@ -847,6 +847,9 @@ async def test_id_conflict_policy_fail(client: Client, env: WorkflowEnvironment) id_conflict_policy=ActivityIDConflictPolicy.FAIL, ) assert err.value.activity_id == activity_id + assert "Activity" in str( + err.value + ), f"Expected 'Activity' in error message, got: {err.value}" async def test_id_conflict_policy_use_existing( From 3f852fe1ed7f267c165d32d849ec3e813eaa9b68 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Fri, 27 Feb 2026 22:05:39 -0500 Subject: [PATCH 2/3] Fix --- temporalio/exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/temporalio/exceptions.py b/temporalio/exceptions.py index 8f0423153..d386d4327 100644 --- a/temporalio/exceptions.py +++ b/temporalio/exceptions.py @@ -83,8 +83,8 @@ class ActivityAlreadyStartedError(FailureError): def __init__( self, activity_id: str, activity_type: str, *, run_id: str | None = None ) -> None: - """Initialize a workflow already started error.""" - super().__init__("Workflow execution already started") + """Initialize an activity already started error.""" + super().__init__("Activity execution already started") self.activity_id = activity_id self.activity_type = activity_type self.run_id = run_id From 48832d6d69489414ddd96e505cf7a8108c48ebfd Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Mon, 2 Mar 2026 09:36:43 -0500 Subject: [PATCH 3/3] rm repro script --- .../repro_activity_already_started_error.py | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 scripts/repro_activity_already_started_error.py diff --git a/scripts/repro_activity_already_started_error.py b/scripts/repro_activity_already_started_error.py deleted file mode 100644 index fb25d6b7c..000000000 --- a/scripts/repro_activity_already_started_error.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env -S uv run --script -# -# /// script -# requires-python = ">=3.12" -# dependencies = ["temporalio"] -# /// -"""Repro: ActivityAlreadyStartedError contains wrong error message. - -The error message says "Workflow execution already started" when it should say -"Activity execution already started". - -This script demonstrates the bug without needing a Temporal server by simply -constructing the exception and printing its message. -""" - -from temporalio.exceptions import ActivityAlreadyStartedError, WorkflowAlreadyStartedError - -print("=== ActivityAlreadyStartedError message bug repro ===\n") - -wf_err = WorkflowAlreadyStartedError("wf-id", "MyWorkflow", run_id="run-1") -act_err = ActivityAlreadyStartedError("act-id", "MyActivity", run_id="run-1") - -print(f"WorkflowAlreadyStartedError message: {wf_err}") -print(f"ActivityAlreadyStartedError message: {act_err}") -print() - -if str(act_err) == str(wf_err): - print("BUG: Both errors have the same message!") - print(f" Both say: \"{act_err}\"") - print(" ActivityAlreadyStartedError should say \"Activity execution already started\"") -else: - print("OK: Error messages are distinct (bug is fixed).")