Temporal.io Python SDK
raw JSON → 1.24.0 verified Tue May 12 auth: no python install: draft
The Temporal.io Python SDK (current version 1.24.0) provides a framework for authoring durable workflows and activities using the Python programming language. It enables developers to build resilient, scalable, and fault-tolerant applications that can execute long-running business logic reliably. The library maintains a regular release cadence, often with monthly or bi-monthly updates, introducing new features, improvements, and bug fixes.
pip install temporalio Common errors
error grpc._channel._MultiThreadedRendezvous: <_MultiThreadedRendezvous of RPC that terminated with: status = StatusCode.UNAVAILABLE ↓
cause The Temporal client cannot establish a connection with the Temporal server, usually because the server is not running or is unreachable at the specified address.
fix
Ensure the Temporal server is running and confirm the
target_host (e.g., localhost:7233) used in Client.connect() matches the server's address and port. error ApplicationError: type='temporal.workflow.NotFound', message='Workflow with name "MyWorkflow" is not registered on the worker.' ↓
cause The worker instance has not been configured to register the workflow class, or the task queue used to start the workflow does not match the worker's task queue.
fix
Add the workflow class to the worker's
workflows list and ensure the worker's task_queue argument matches the task queue specified when starting the workflow. Example: Worker(client, task_queue='my-task-queue', workflows=[MyWorkflow]). error RuntimeError: Workflow must not 'await' non-Temporal futures. Instead, use 'temporalio.workflow.asyncio.sleep', 'temporalio.workflow.asyncio.wait', etc. ↓
cause Temporal workflows require deterministic execution and cannot directly await arbitrary Python `asyncio` futures or blocking calls; they must use Temporal's specific asynchronous primitives or delegate to activities.
fix
Replace non-Temporal
await calls (e.g., await asyncio.sleep(), await aiohttp.get()) with their deterministic Temporal counterparts (e.g., await workflow.sleep()) or encapsulate the non-deterministic logic within a Temporal Activity. error ModuleNotFoundError: No module named 'temporalio' ↓
cause The `temporalio` Python SDK library has not been installed in the current Python environment.
fix
Install the library using pip:
pip install temporalio. Warnings
breaking Python 3.9 support was removed in version 1.19.0 as it reached End-of-Life. Users on Python 3.9 must upgrade to Python 3.10 or newer. ↓
fix Upgrade Python environment to 3.10 or a later supported version.
breaking In version 1.23.0, fields `workflow_id`, `workflow_namespace`, `workflow_run_id`, and `workflow_type` within `activity.Info` were made optional. Additionally, `converter.BaseWorkflowSerializationContext` was removed. ↓
fix Adjust code that manually accesses `activity.Info` fields to handle potential `None` values. Refactor any custom `BaseWorkflowSerializationContext` subclasses.
breaking Version 1.24.0 introduces general availability for Nexus and OpenAI Agents SDK Integration. It also includes new OpenTelemetry integration for OpenAI Agents, which may cause conflicts or require adjustments for existing custom OpenTelemetry setups. ↓
fix Review and update OpenTelemetry tracing configurations if using OpenAI Agents with custom instrumentation. Leverage the GA features of Nexus and OpenAI Agents.
gotcha Beginning with version 1.21.0, providing an `api_key` to `Client.connect` automatically enables TLS. ↓
fix If you wish to use an `api_key` without TLS, explicitly pass `tls=False` to `Client.connect`.
gotcha The Workflow Sandbox isolates workflow code to ensure determinism. Importing non-standard library or non-`temporalio` modules directly into workflow files can lead to `RestrictedWorkflowAccessError` or non-determinism. ↓
fix For modules needed only by activities, import them within the activity function, or use `with workflow.unsafe.imports_passed_through(): import my_module` when importing them into workflow files. For performance, pass through any side-effect-free third-party libraries explicitly.
breaking Installing `temporalio` on Alpine Linux (especially with newer Python versions for which pre-built wheels may not exist) can fail due to missing build dependencies like `libgcc_s.so.1` or incompatible Rust compilation. Alpine's musl libc often requires specific system packages or a different Rust target to successfully compile native extensions. ↓
fix On Alpine Linux, ensure `build-base`, `gcc`, `g++`, and `rustup` (with the `x86_64-unknown-linux-musl` target) are installed in the build environment. For simpler deployments, consider using a glibc-based Python image (e.g., Debian-based) where pre-built `temporalio` wheels are more commonly available.
Install compatibility draft last tested: 2026-05-12
python os / libc status wheel install import disk
3.10 alpine (musl) build_error - - - -
3.10 alpine (musl) - - - -
3.10 slim (glibc) wheel 3.0s 0.43s 75M
3.10 slim (glibc) - - 0.43s 73M
3.11 alpine (musl) build_error - - - -
3.11 alpine (musl) - - - -
3.11 slim (glibc) wheel 2.9s 1.08s 78M
3.11 slim (glibc) - - 1.07s 75M
3.12 alpine (musl) build_error - - - -
3.12 alpine (musl) - - - -
3.12 slim (glibc) wheel 2.6s 1.25s 70M
3.12 slim (glibc) - - 1.31s 67M
3.13 alpine (musl) build_error - - - -
3.13 alpine (musl) - - - -
3.13 slim (glibc) wheel 2.9s 1.17s 69M
3.13 slim (glibc) - - 1.24s 67M
3.9 alpine (musl) build_error - - - -
3.9 alpine (musl) - - - -
3.9 slim (glibc) wheel 3.4s 0.41s 67M
3.9 slim (glibc) - - 0.47s 67M
Imports
- Client
from temporalio.client import Client - Worker
from temporalio.worker import Worker - workflow
from temporalio import workflow - activity
from temporalio import activity - workflow.unsafe.imports_passed_through
from temporalio import workflow with workflow.unsafe.imports_passed_through(): from my_app import my_activity_module
Quickstart last tested: 2026-04-24
import asyncio
from datetime import timedelta
from temporalio.client import Client
from temporalio.worker import Worker
from temporalio import activity, workflow
# Define an activity
@activity.defn
async def say_hello(name: str) -> str:
return f"Hello, {name}!"
# Define a workflow
@workflow.defn
class GreetingWorkflow:
@workflow.run
async def run(self, name: str) -> str:
return await workflow.execute_activity(
say_hello,
name,
schedule_to_close_timeout=timedelta(seconds=5),
)
async def main():
# Connect to Temporal server (default to localhost:7233)
# Use os.environ.get('TEMPORAL_HOST_PORT', 'localhost:7233') for dynamic connection
client = await Client.connect(os.environ.get('TEMPORAL_HOST_PORT', 'localhost:7233'))
# Run a worker
task_queue_name = "my-task-queue"
worker = Worker(
client,
task_queue=task_queue_name,
workflows=[GreetingWorkflow],
activities=[say_hello],
)
# Start worker in background
worker_task = asyncio.create_task(worker.run())
print(f"Worker started on task queue '{task_queue_name}'...")
# Start a workflow execution
result = await client.execute_workflow(
GreetingWorkflow.run,
"Temporal",
id="greeting-workflow-id",
task_queue=task_queue_name,
)
print(f"Workflow result: {result}") # Expected: "Hello, Temporal!"
# Clean up worker
worker_task.cancel()
await worker_task
if __name__ == "__main__":
import os
asyncio.run(main())