You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A list item field with value 'PT' being converted to Datetime object #1340
I am trying to iterate through a SharePoint list entries/rows for further processing:
...
list = await client.sites.by_site_id(site_id).lists.by_list_id(list_id).items.get(request_configuration=request_config)
rows = []
for item_id in list.value:
fields = item_id['fields']
rows.append(fields.additional_data.get("code")) # test
rows
but when text/string field have value 'PT' it is retrieved as a datetime (exactly: "datetime.timedelta(0)"). It makes my code useless for keeping for example 'Country Code' as list's field. I have seen similar issue before with 4-digit strings, so maybe it is related.
Please, take a moment to look at this.
here some screenshots:
list in SP (just field 'code' and its values) :
and my code results:
Expected behavior
Expected behavior would be to display 'code' the same way as it is in SharePoint list, means:
PT
PTA
..
How to reproduce
To reproduce please just create new list with text field. Then add value 'PT' to this field and try to use await client.sites.by_site_id(site_id).lists.by_list_id(list_id).items.get(request_configuration=request_config) for entried reading.
SDK Version
1.40.0
Latest version known to work for scenario above?
No response
Known Workarounds
No response
Debug output
Click to expand log
```
</details>
### Configuration
_No response_
### Other information
_No response_
Luis Ramos (@lramosvea) We hit the same bug in a production AP-invoicing app, and in our case it caused actual data corruption, not just display errors. We've also traced the root cause to the exact lines in kiota and have a tested fix — details below.
Real captured wire payload
Live tenant, PII redacted. InvoiceId is a "Single line of text" column:
That stored value was originally the invoice number 19-2026 (visible in the document filename). Kiota parsed "19-2026" as 19:00 with a UTC offset of -20:26 fabricated from the year fragment "-2026"; the app later stringified the object on an update and the mangled value is now what's persisted. We found three invoices corrupted this way (18-2026, 19-2026, 20-2026). Any invoice number ending in a plausible-offset suffix does this — for us, that's every invoice numbered with the current year.
Root cause
JsonParseNode.try_get_anything in microsoft-kiota-serialization-json (json_parse_node.py) speculatively runs every untyped string (i.e. everything landing in additional_data) through five lenient parsers in sequence: datetime_from_iso_format_compat, UUID, parse_timedelta_string, date.fromisoformat, time_from_iso_format_compat.
The killer is the last one: on Python 3.11+, time.fromisoformat accepts strings like "19-2026" (hour 19, offset -20:26) and "23.085" (23:00:00.085). parse_timedelta_string accepts "PT" (empty ISO-8601 duration → timedelta(0)) and "10:30" (hh:mm). None of these are plausible as JSON wire formats for time values.
Minimal repro, no Graph call needed (microsoft-kiota-serialization-json 1.9.3, Python 3.12.10):
('11.0' explains the _UIVersionString corruption shown earlier in this thread.)
The existing __is_four_digit_number / isdigit() guards (added for earlier reports like #653) patch individual symptoms but leave the underlying speculative parsing in place, which is why this class of bug keeps coming back.
Proposed fix
The .NET serializer already does this right: JsonParseNode.TryGetAnything only attempts strictDateTime/DateTimeOffset/Guid parses on strings and otherwise returns the string — it never guesses TimeSpan/TimeOnly/DateOnly. Aligning Python with that:
Routing date-only strings through datetime_from_iso_format_compat deliberately preserves the current datetime (not date) result, so real Graph payloads (Created, Modified, date columns) behave identically — the only behavior change is that strings which were never date/time/duration values stay strings.
The timedelta guess has to go entirely: Graph never sends bare durations in untyped additional_data, and ISO-8601 durations (P.../PT...) overlap with too many real-world strings.
The __is_four_digit_number and isdigit() special cases become unnecessary (all-digit strings can't match either anchored pattern) and can be deleted.
Typed model fields are unaffected — they go through declared field deserializers and never reach try_get_anything.
Happy to open a PR against microsoft/kiota-python with this change and tests if the maintainers agree with the direction.
Environment: msgraph-sdk 1.37.0, msgraph-core 1.3.4, microsoft-kiota-serialization-json 1.9.3, Python 3.12.10. The same code is present on kiota-python main today.
Follow-up: opened microsoft/kiota-python#664 with the fix described above (strict anchored date/datetime/UUID matching in try_get_anything, mirroring the .NET serializer) plus regression tests covering every corruption pattern reported in this thread.
Activity
mkkubins commentedon Jan 27, 2026
I have similar issue that
textcolumn is converted todatetime.time:'xxx': datetime.time(10, 0, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=20280))),smonsalve-IMC commentedon Apr 13, 2026
Similar issue:
The raw Graph API wire payload is
column
but
item.fields.additional_data["column_name"]returns
datetime.time(23, 0, 0, 85000)after Kiota parsing.
Environment
lramosvea commentedon May 18, 2026
Hi Tomasz Ratynski (@SirTomRat), smonsalve-IMC , mkkubins could you please share the JSON response you are getting?
SirTomRat commentedon May 25, 2026
Luis Ramos (@lramosvea)
json for existing two rows looks like that:
{'ID': '1', 'fields': FieldValueSet(additional_data={'@odata.etag': '"5674dfd1-047b-4b9d-a49a-4a34c9263872,11"', 'Title': 'aa', 'LinkTitleNoMenu': 'aa', 'Category': 'categpry1', 'code1': datetime.time(1, 0), 'ContentType': 'Item', 'Modified': datetime.datetime(2026, 2, 11, 13, 48, 2, tzinfo=datetime.timezone.utc), 'Created': datetime.datetime(2025, 7, 2, 10, 40, 36, tzinfo=datetime.timezone.utc), 'AuthorLookupId': '13', 'EditorLookupId': '13', '_UIVersionString': datetime.time(11, 0), 'Attachments': False, 'Edit': '', 'LinkTitle': 'aa', 'ItemChildCount': '0', 'FolderChildCount': '0', '_ComplianceFlags': '', '_ComplianceTag': '', '_ComplianceTagWrittenTime': '', '_ComplianceTagUserId': '', 'AppAuthorLookupId': '18'}, id='1', odata_type=None), 'Created By': 'xyz', 'Modified By': 'xyz'}
{'ID': '2', 'fields': FieldValueSet(additional_data={'@odata.etag': '"765b81af-1e73-4d93-aa80-d2d8bd8f9988,1"', 'Title': 'bb', 'LinkTitleNoMenu': 'bb', 'Category': datetime.timedelta(0), 'code1': 'ff', 'ContentType': 'Item', 'Modified': datetime.datetime(2026, 5, 25, 7, 6, 29, tzinfo=datetime.timezone.utc), 'Created': datetime.datetime(2026, 5, 25, 7, 6, 29, tzinfo=datetime.timezone.utc), 'AuthorLookupId': '13', 'EditorLookupId': '13', '_UIVersionString': '1.0', 'Attachments': False, 'Edit': '', 'LinkTitle': 'bb', 'ItemChildCount': '0', 'FolderChildCount': '0', '_ComplianceFlags': '', '_ComplianceTag': '', '_ComplianceTagWrittenTime': '', '_ComplianceTagUserId': '', 'AppAuthorLookupId': '18', 'AppEditorLookupId': '18'}, id='2', odata_type=None), 'Created By': 'xyz', 'Modified By': 'xyz'}
for the SharePoint list:

56badkarma commentedon Jul 18, 2026
Luis Ramos (@lramosvea) We hit the same bug in a production AP-invoicing app, and in our case it caused actual data corruption, not just display errors. We've also traced the root cause to the exact lines in kiota and have a tested fix — details below.
Real captured wire payload
Live tenant, PII redacted.
InvoiceIdis a "Single line of text" column:{ "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('...')/lists('...')/items(fields(InvoiceId))/$entity", "@odata.etag": "\"1342017a-ff3b-463c-a6e3-cefaf61836f0,13\"", "id": "42151", "webUrl": "https://<tenant>.sharepoint.com/sites/<site>/Extraction%20Library/INV%2019%202026_....pdf", "fields": { "@odata.etag": "\"1342017a-ff3b-463c-a6e3-cefaf61836f0,13\"", "InvoiceId": "19:00:00-20:26" } }That stored value was originally the invoice number
19-2026(visible in the document filename). Kiota parsed"19-2026"as 19:00 with a UTC offset of -20:26 fabricated from the year fragment "-2026"; the app later stringified the object on an update and the mangled value is now what's persisted. We found three invoices corrupted this way (18-2026,19-2026,20-2026). Any invoice number ending in a plausible-offset suffix does this — for us, that's every invoice numbered with the current year.Root cause
JsonParseNode.try_get_anythinginmicrosoft-kiota-serialization-json(json_parse_node.py) speculatively runs every untyped string (i.e. everything landing inadditional_data) through five lenient parsers in sequence:datetime_from_iso_format_compat,UUID,parse_timedelta_string,date.fromisoformat,time_from_iso_format_compat.The killer is the last one: on Python 3.11+,
time.fromisoformataccepts strings like"19-2026"(hour 19, offset -20:26) and"23.085"(23:00:00.085).parse_timedelta_stringaccepts"PT"(empty ISO-8601 duration →timedelta(0)) and"10:30"(hh:mm). None of these are plausible as JSON wire formats for time values.Minimal repro, no Graph call needed (
microsoft-kiota-serialization-json1.9.3, Python 3.12.10):(
'11.0'explains the_UIVersionStringcorruption shown earlier in this thread.)The existing
__is_four_digit_number/isdigit()guards (added for earlier reports like #653) patch individual symptoms but leave the underlying speculative parsing in place, which is why this class of bug keeps coming back.Proposed fix
The .NET serializer already does this right:
JsonParseNode.TryGetAnythingonly attempts strictDateTime/DateTimeOffset/Guidparses on strings and otherwise returns the string — it never guesses TimeSpan/TimeOnly/DateOnly. Aligning Python with that:Verified against both the failure cases and the values that must keep converting:
"19-2026"time(19, 0, tz-20:26)"19-2026"✅"100-012863299"time(10, 0, ...)"PT"timedelta(0)"PT"✅"10:30"timedelta(seconds=37800)"10:30"✅"23.085"time(23, 0, 0, 85000)"23.085"✅"11.0"time(11, 0)"11.0"✅"d41d8cd98f00b204e9800998ecf8427e"UUID(...)"2026-02-11T13:48:02Z"datetime(...)datetime(...)— unchanged"2026-02-11"datetime(2026, 2, 11, 0, 0)datetime(2026, 2, 11, 0, 0)— unchanged"9f614123-06fb-...-5bb014d7d3c4"UUID(...)UUID(...)— unchangedNotes:
datetime_from_iso_format_compatdeliberately preserves the currentdatetime(notdate) result, so real Graph payloads (Created,Modified, date columns) behave identically — the only behavior change is that strings which were never date/time/duration values stay strings.timedeltaguess has to go entirely: Graph never sends bare durations in untypedadditional_data, and ISO-8601 durations (P.../PT...) overlap with too many real-world strings.__is_four_digit_numberandisdigit()special cases become unnecessary (all-digit strings can't match either anchored pattern) and can be deleted.try_get_anything.Happy to open a PR against microsoft/kiota-python with this change and tests if the maintainers agree with the direction.
Environment: msgraph-sdk 1.37.0, msgraph-core 1.3.4, microsoft-kiota-serialization-json 1.9.3, Python 3.12.10. The same code is present on kiota-python
maintoday.Related: #653 (2024, closed without addressing the root cause), microsoft/kiota-python#487.
56badkarma commentedon Jul 18, 2026
Follow-up: opened microsoft/kiota-python#664 with the fix described above (strict anchored date/datetime/UUID matching in
try_get_anything, mirroring the .NET serializer) plus regression tests covering every corruption pattern reported in this thread.56badkarma commentedon Aug 19, 2026
microsoft/kiota-python/pull/664
merged and released last week. I would reccomend closing this issue.