Skip to content

[Bug] Canceling a workflow with a child causes non-determinism warning #906

Open
@dandavison

Description

@dandavison

[This is not really a bug report; more a question about whether a worrying-sounding warning can be avoided.]

The code below frequently results in the following warning being emitted:

2025-04-22T15:13:47.323178Z  WARN temporal_sdk_core::worker::workflow: Failing workflow task run_id=01965e0f-f936-7177-b305-37b937721f34 failure=Failure { failure: Some(Failure { message: "Fatal error in workflow machines: Invalid transition while attempting to cancel ChildWorkflowMachine in StartEventRecorded", source: "", stack_trace: "", encoded_attributes: None, cause: None, failure_info: Some(ApplicationFailureInfo(ApplicationFailureInfo { r#type: "", non_retryable: false, details: None, next_retry_delay: None })) }), force_cause: Unspecified }

Since the code is using APIs in a recommended way, it seems wrong for it to routinely cause a warning (and odd that the warning describes itself as a fatal error).

#!/usr/bin/env uv run
import asyncio
import uuid

from temporalio import workflow
from temporalio.client import Client
from temporalio.worker import UnsandboxedWorkflowRunner, Worker

CHILD_WORKFLOW_ID = f"cwid-{uuid.uuid4()}"
WORKFLOW_ID = f"wid-{uuid.uuid4()}"
TASK_QUEUE = "tq"


@workflow.defn
class ChildWorkflow:
    @workflow.run
    async def run(self) -> None:
        await asyncio.Future()


@workflow.defn
class ParentWorkflow:
    @workflow.run
    async def run(self) -> None:
        child_handle = await workflow.start_child_workflow(
            ChildWorkflow.run, id=CHILD_WORKFLOW_ID
        )
        await child_handle


async def main():
    client = await Client.connect("localhost:7233")

    async with Worker(
        client,
        task_queue=TASK_QUEUE,
        workflows=[ParentWorkflow, ChildWorkflow],
        workflow_runner=UnsandboxedWorkflowRunner(),
    ):
        handle = await client.start_workflow(
            ParentWorkflow.run, id=WORKFLOW_ID, task_queue=TASK_QUEUE
        )
        await handle.cancel()
        await handle.result()


if __name__ == "__main__":
    asyncio.run(main())

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions