Skip to content

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

Merged
maciejdudko merged 1 commit into
temporalio:mainfrom
LindseyZ1205:fix/activity-expiration-time-none
Oct 27, 2026
Merged

maciejdudko merged 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

@maciejdudko maciejdudko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @LindseyZ1205, thank you for your contribution! The code looks good and the tests pass, LGTM!

@maciejdudko
maciejdudko merged commit dbb8552 into temporalio:main Oct 27, 2026
34 of 36 checks passed
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