{"id":9278,"library":"restate-sdk","title":"Restate Python SDK","description":"The `restate-sdk` is a Python SDK for Restate, a platform designed for building resilient applications using distributed durable async/await. It enables developers to implement durable backend services, virtual objects, and AI agents that can withstand failures and manage state reliably. The library is actively maintained with frequent minor version releases, integrating new features and improvements often.","status":"active","version":"0.17.1","language":"en","source_language":"en","source_url":"https://github.com/restatedev/sdk-python","tags":["distributed systems","serverless","workflow","durable execution","async","ai agents"],"install":[{"cmd":"pip install restate-sdk","lang":"bash","label":"Base installation"},{"cmd":"pip install restate-sdk[serde]","lang":"bash","label":"With msgspec for enhanced serialization"},{"cmd":"pip install restate-sdk[openai-agents]","lang":"bash","label":"With OpenAI Agents SDK integration"},{"cmd":"pip install restate-sdk[harness]","lang":"bash","label":"With testing harness (Testcontainers, pytest)"}],"dependencies":[{"reason":"Used for advanced serialization with the 'serde' extra.","package":"msgspec","optional":true},{"reason":"Used for native integration with OpenAI Agents SDK.","package":"openai-agents","optional":true},{"reason":"Testing utility part of the 'harness' extra.","package":"pytest","optional":true},{"reason":"Used by the testing harness to run a Restate Server in Docker.","package":"Testcontainers","optional":true}],"imports":[{"note":"The primary import for accessing SDK components like Service, Context, and app.","symbol":"restate","correct":"import restate"},{"note":"Service is typically accessed via the top-level 'restate' import.","wrong":"import Service","symbol":"Service","correct":"from restate import Service"},{"note":"Context is typically accessed via the top-level 'restate' import and passed to handlers.","wrong":"import Context","symbol":"Context","correct":"from restate import Context"},{"note":"The 'app' factory function is typically accessed via the top-level 'restate' import for serving services.","wrong":"import app","symbol":"app","correct":"from restate import app"},{"note":"TerminalError is in the `restate.exceptions` submodule, not directly under `restate`.","wrong":"from restate import TerminalError","symbol":"TerminalError","correct":"from restate.exceptions import TerminalError"}],"quickstart":{"code":"import restate\n\nmy_service = restate.Service(\"MyService\")\n\n@my_service.handler(\"greet\")\nasync def greet(ctx: restate.Context, name: str) -> str:\n    # Use ctx.run to wrap any non-deterministic operations or external calls\n    # For this simple example, we'll just return a greeting.\n    return f\"Hello {name}!\"\n\n# To run the service, typically you'd run this file with 'restate serve'\n# or deploy it to a Restate runtime. For local testing, you can use:\n# (This part is not runnable without a Restate runtime running)\n# app = restate.app([my_service])\n# app.run() # This would start an HTTP server\n\n# Example of how to call this service (requires a running Restate server)\nasync def call_service_example():\n    # This client creation is for an ingress client (v0.12.0+)\n    async with restate.create_client(\"http://localhost:8080\") as client:\n        # Assuming 'MyService' is registered and 'greet' handler is available\n        result = await client.object_call(my_service, key=\"unique-key\", handler_name=\"greet\", arg=\"World\")\n        print(f\"Service call result: {result}\")\n\nif __name__ == \"__main__\":\n    # For a full local setup and run, refer to Restate's Python Quickstart documentation.\n    # The provided code snippet defines a service, but doesn't run it as a standalone app\n    # without a Restate server or the 'restate serve' command.\n    import asyncio\n    # asyncio.run(call_service_example()) # Uncomment to try calling (requires Restate server)\n    print(\"Service 'MyService' with handler 'greet' defined. To run, use 'restate serve'.\")","lang":"python","description":"This quickstart defines a basic Restate service named 'MyService' with a single asynchronous handler 'greet'. Handlers receive a `restate.Context` object for durable operations and can process input to produce an output. To execute this service, it needs to be run within a Restate runtime environment, typically by using the `restate serve` CLI command after defining the service."},"warnings":[{"fix":"Upgrade your `restate-sdk` to version 0.6 or higher. After upgrading, re-register your deployment with the Restate server.","message":"SDK versions prior to 0.6 are deprecated and will be rejected by Restate server versions 1.5 and above. This can lead to registration failures for services deployed with older SDKs.","severity":"breaking","affected_versions":"<0.6"},{"fix":"Review and explicitly configure the retry policy for your LLM calls if the new defaults are not suitable for your application. This can often be done via service or handler-level configurations.","message":"The default retry strategy for LLM calls within Restate AI integrations (e.g., `pydantic-ai`) changed in v0.16.0. It now defaults to 10 attempts with a 1-second minimum interval, potentially altering the behavior of existing AI agent workflows.","severity":"breaking","affected_versions":"0.16.0+"},{"fix":"Always catch specific exceptions. For permanent, non-retryable errors, explicitly raise `restate.exceptions.TerminalError`. For transient errors, let them propagate to trigger Restate's built-in retry mechanism.","message":"Using broad exception handling like `except Exception:` or bare `except:` in Restate handlers is highly discouraged. This can inadvertently catch internal SDK exceptions, leading to non-deterministic behavior and breaking Restate's durable execution guarantees.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure your Restate SDK version is compatible with your Restate server version. Refer to the official Restate documentation for compatibility matrices. Upgrade either the SDK or the server as necessary.","message":"Incompatible versions between the Restate SDK and the Restate server can lead to runtime errors like 'Protocol violation error' (RT0012) or 'The service endpoint does not support any of the supported service protocol versions of the server' (RT0013).","severity":"gotcha","affected_versions":"All versions"},{"fix":"If you are using these advanced configuration options, ensure your Restate server is at least version 1.4 or 1.5, depending on the specific feature. Consult the in-code documentation or Restate release notes for exact version requirements.","message":"New service/object/workflow constructor fields and handler decorator fields (e.g., `inactivity_timeout`, `abort_timeout`, `invocation_retry_policy`) only function correctly with Restate server versions 1.4 or 1.5 and newer.","severity":"gotcha","affected_versions":"All versions if using older Restate Server"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Check the Restate documentation for SDK-server compatibility. Upgrade your `restate-sdk` package or the Restate server to compatible versions.","cause":"The Restate Python SDK version is incompatible with the Restate server version it's trying to communicate with.","error":"Protocol violation error (RT0012) OR The service endpoint does not support any of the supported service protocol versions of the server (RT0013)"},{"fix":"For errors that should not be retried (e.g., invalid input, business logic violations), raise `restate.exceptions.TerminalError('My error message')` in your handler.","cause":"Restate, by default, retries all errors unless explicitly marked as terminal. Your application-specific error is being treated as a transient failure.","error":"My Restate service keeps retrying indefinitely for an application-specific error, instead of failing permanently."},{"fix":"Wrap all external calls, non-deterministic computations, or any operation that should only execute once and whose result needs to be durable, inside `await ctx.run(\"unique-name\", lambda: my_nondeterministic_op())`.","cause":"External, non-deterministic operations or side effects are not being wrapped correctly within `ctx.run` blocks, which ensure their results are journaled and replayed consistently.","error":"Non-deterministic behavior or unexpected state during replays when interacting with external systems (e.g., HTTP calls, random numbers)."}]}