Azure / Azure/azure-sdk-for-python

Cosmos - Change Feed Continuation Token Parsing Bug

Open
#43,018 2 comments 0 reactions 1 assignee Claimed by @allenkim0129 View on GitHub
Client Cosmos customer-reported needs-team-attention question Service Attention
Dominant language
Python
Stars
5.6k
Forks
3.4k
Avg merge
1d 21h
Merged PRs (30d)
193

Description

- **Package Name**: azure-cosmos
- **Package Version**: 4.9.0
- **Operating System**: Debian
- **Python Version**: 3.12.11

**Describe the bug**

Using the `ContainerProxy.query_items_change_feed` with the `continuation` fails with a ValueError when provided a valid continuation token returned by Cosmos DB (NoSQL mode). Example error:

```
ValueError: year 57679 is out of range
```

**To Reproduce**
Steps to reproduce the behavior:
1. Create a Cosmos NoSQL account, database and container
2. Using the Python SDK, call `query_items_change_feed` on the container instance with a `start_time` parameter supplied.
3. Capture the continuation token from `client_connection.last_response_headers["etag"]`
4. Call `query_items_change_feed` on the container instance with the `continuation` parameter set to the value from 3.

**Expected behavior**
No errors should occur, the change feed query should return expected results, allowing a client to persist the continuation token and pull down further change feed information.

**Additional context**

This is happening due to bad handling of the continuation token. At `azure/cosmos/_change_feed/change_feed_start_from.py:198`, the SDK attempts to parse the point in time with the following:

```python
point_in_time = datetime.fromtimestamp(point_in_time_ms).astimezone(timezone.utc)
```

However, the relevant part of the base64 encoded continuation token has the time present as a Unix timestamp in milliseconds, example extracted from a token:

```json
{"Type": "PointInTime", "PointInTimeMs": 1758011093508}
```

The `from_timestamp` method expects a Unix timestamp **in seconds**. Hence passing the timestamp in milliseconds is causing the `ValueError`. The variable is called `point_in_time_ms` which is correct but this is not being used correctly. One possible fix is something like:

```python
point_in_time = datetime.fromtimestamp(point_in_time_ms / 1000).astimezone(timezone.utc) + timedelta(milliseconds=point_in_time_ms % 1000)
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.