I'm using Event delta queries API to synchronize calendar events for several account.
The initial /calendar/calendarView/delta request spans a 1-year window, from now to 1 year in the future.
With one specific account, the delta request return an infinite number of pages, all with the same contents.
The response to /delta request contains a @odata.nextLink property pointing to the next page of results.
The second page of results is actually different from the first page, and contains another nextLink for the third page.
After that, all subsequent requests will return the same page contents.
Note that the nextLink is always different on each page (seems legit), but the only difference from one response to the next is the nextLink itself.
The loop will go on forever, always downloading the same content.
I wrote a small bash script to demonstrate the issue, writing the JSON responses to disk (one file per page):
#!/bin/sh
export ACCESS_TOK='ey...'
# Page number
N=0
# Output file (one per page)
outf="${N}.json"
curl --get -v -H 'Authorization: Bearer '${ACCESS_TOK} \
'https://graph.microsoft.com/v1.0/users/*****@*****.com/calendar/calendarView/delta' \
--data-urlencode 'startDateTime=2026-02-26T15:00:00+0100' \
--data-urlencode 'endDateTime=2027-02-26T15:00:00+0100' >${outf}
N=$((N+1))
while true ; do
nextL=`jq -r '."@odata.nextLink"' ${outf}`
[[ "$nextL" == "null" ]] && break
outf=${N}.json
echo "req: $nextL"
# Follow nextLink
curl -H 'Authorization: Bearer '${ACCESS_TOK} \
"${nextL}" >${outf}
N=$((N+1))
done
... and stopped it after 4587 pages and 861MB of downloaded content.
-rw-r--r-- 1 calsync calsync 199525 Feb 25 15:59 0.json
-rw-r--r-- 1 calsync calsync 195225 Feb 25 15:59 1.json
-rw-r--r-- 1 calsync calsync 195225 Feb 25 15:59 2.json
-rw-r--r-- 1 calsync calsync 195225 Feb 25 15:59 3.json
-rw-r--r-- 1 calsync calsync 195225 Feb 25 15:59 4.json
... ... ...
... ... ...
-rw-r--r-- 1 calsync calsync 195225 Feb 25 16:30 4585.json
-rw-r--r-- 1 calsync calsync 195225 Feb 25 16:30 4586.json
-rw-r--r-- 1 calsync calsync 195225 Feb 25 16:30 4587.json
As you can see here, i used jq to format the JSON files in order to diff them more easily.
In the ~190k of payload, the only thing that changes from one page to another (except page zero) is the nextLink:
$ diff <(jq . 1.json) <(jq . 2.json)
4837c4837
< "@odata.nextLink": "https://graph.microsoft.com/v1.0/users/*****@*****.com/calendar/calendarView/delta?$skiptoken=3jcBbtAJKmoRXgEi7wAb_b-SnM7RKiISGlxJAy7BDn7aM2vqoQuAPxccRYP4_Tux66HiXGWtsIfug5zkH1mMoFlNIuQpw7GCRaL-zLosn2SkVr7vHT_fUUPMANRBa7tYB8XTL1R_qrZFkjGNLA7GWQvEX2RVfyMSvE7IAAele0dZuYBDOyzfDuesGU0SB-9j4Hsg3I5vRuKv5_FGhHU1mOLg_8WtM5Hc5_OGliG2oYMI6PvpQOiwN8XBqPEhH6A-6fEazgh_PbId8X6py93j1g.y0hlsZbeZARizXvTqxcMjWcV9yV65K8MzLwAMee33Mo"
---
> "@odata.nextLink": "https://graph.microsoft.com/v1.0/users/*****@*****.com/calendar/calendarView/delta?$skiptoken=3jcBbtAJKmoRXgEi7wAb_b-SnM7RKiISGlxJAy7BDn7aM2vqoQuAPxccRYP4_Tux66HiXGWtsIfug5zkH1mMoFlNIuQpw7GCRaL-zLosn2SkVr7vHT_fUUPMANRBa7tYmc7PT1BmZ6_ay1eBkiRy66vv0-ul3kufSSlfyfr8DiBFef8O0N8BEajVKudMjW61LaNfLntk521MRvdrdMgNoGRGPHhCfwI7cFV9yzyHYiuLTvmdeGODzi7mME9YT1SMaRK80Yel1BiDrPPN6gDuZw.Eo3gVAnWzr_rRvU3J2a_OCI2olGSJHlG4jWW1lYRUig"
$ diff <(jq . 1.json) <(jq . 4587.json)
4837c4837
< "@odata.nextLink": "https://graph.microsoft.com/v1.0/users/*****@*****.com/calendar/calendarView/delta?$skiptoken=3jcBbtAJKmoRXgEi7wAb_b-SnM7RKiISGlxJAy7BDn7aM2vqoQuAPxccRYP4_Tux66HiXGWtsIfug5zkH1mMoFlNIuQpw7GCRaL-zLosn2SkVr7vHT_fUUPMANRBa7tYB8XTL1R_qrZFkjGNLA7GWQvEX2RVfyMSvE7IAAele0dZuYBDOyzfDuesGU0SB-9j4Hsg3I5vRuKv5_FGhHU1mOLg_8WtM5Hc5_OGliG2oYMI6PvpQOiwN8XBqPEhH6A-6fEazgh_PbId8X6py93j1g.y0hlsZbeZARizXvTqxcMjWcV9yV65K8MzLwAMee33Mo"
---
> "@odata.nextLink": "https://graph.microsoft.com/v1.0/users/*****@*****.com/calendar/calendarView/delta?$skiptoken=3jcBbtAJKmoRXgEi7wAb_b-SnM7RKiISGlxJAy7BDn7aM2vqoQuAPxccRYP4_Tux66HiXGWtsIfug5zkH1mMoFlNIuQpw7GCRaL-zLosn2TvJpfKv-_hx9AzlfoD7vjgDwerYtwCYesYPrYCpysQOe51HoPAPmrrVT6hsMpjSzvBDO91Aq2uUBgJgMrd0Pkrb_9Ffo2tdtCSS5pqGzWApTEBinusvQnwuIrZSyAugqhbmqQHANzQFUepUvIzgXEpvYpevOhjckVNQGGxpahXOw.wNwfHHevjZFh1KEuAdNYuuegkwwiNm8Cw2O9Y_1_PG4"
I found many similar reports on the web, regarding other areas of the Graph API, but no clear solution.
https://github.com/OneDrive/onedrive-api-docs/issues/1424
https://github.com/microsoftgraph/msgraph-sdk-javascript/issues/1656
https://dori-uw-1.kuma-moon.com/en-us/answers/questions/5519318/graph-api-groups-delta-query-never-returns-delta-q
Not being able to find useful info, i've made several random tests, and finally discovered a behavior that seems to solve the problem.
My initial /delta request did not specify the optional Prefer: odata.maxpagesize header, leaving the default page size.
If i set it to 2 or 100, the infinite loop does not occur.
If i set it to 2000, or leave it unset, i get the endless loop again.
Did someone experience a similar problem ?
Can someone confirm that explicitly setting the maxsize header is a reliable solution to the problem ?
Thanks,
Alberto