Skip to content

Return None for an unset expiration_time in ActivityHandle.describe() - #2016

Open
LindseyZ1205 wants to merge 1 commit into
temporalio:mainfrom
LindseyZ1205:fix/activity-expiration-time-none
Open

LindseyZ1205 wants to merge 1 commit into
temporalio:mainfrom
LindseyZ1205:fix/activity-expiration-time-none

Conversation

@LindseyZ1205

Copy link
Copy Markdown
Contributor

ActivityExecutionDescription.expiration_time is typed datetime | None, and documented as the time at which the activity's schedule-to-close timeout expires. When a Standalone Activity has no schedule-to-close timeout, for example when it's started with only start_to_close_timeout, the server doesn't set expiration_time, and ActivityHandle.describe() returns datetime.min, which is naive, instead of None. #1782 changed the annotation from datetime to datetime | None, but kept the datetime.min default. NexusOperationExecutionDescription.expiration_time is None in this case.

So code that follows the annotation, such as:

desc = await handle.describe()
if desc.expiration_time is not None:
    remaining = desc.expiration_time - datetime.now(timezone.utc)

raises TypeError: can't subtract offset-naive and offset-aware datetimes for an activity started with only start_to_close_timeout.

This change returns None in this case, and adds a fixed changelog fragment.

test_describe_without_schedule_to_close_timeout in tests/test_activity.py starts an activity with only start_to_close_timeout and checks that describe() returns expiration_time=None. On main, it fails with assert datetime.datetime(1, 1, 1, 0, 0) is None.

Validation, with Python 3.12, the local dev server, and the Rust bridge of the temporalio 1.34.0 wheel:

  • tests/test_activity.py passes (35 tests). I didn't run the rest of the suite, since nothing else in the SDK reads this field.
  • ruff check --select I and ruff format --check (ruff 0.15.22), pyright 1.1.403, basedpyright 1.34.0 and mypy --namespace-packages --check-untyped-defs pass on the changed files, and pydocstyle passes on the changed source file.

ActivityExecutionDescription.expiration_time has been typed
datetime | None since temporalio#1782, but describe() still returned a naive
datetime.min when the server doesn't set it.
@LindseyZ1205
LindseyZ1205 requested a review from a team as a code owner October 23, 2026 19:01

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants