Azure / Azure/azure-cli

`az rest --url` returns malformed pagination URLs causing infinite loops

Open
#32,080 4 comments 1 reaction 3 assignees Claimed by @a0x1ab View on GitHub
Auto-Assign bug customer-reported Service Attention
Dominant language
Python
Stars
4.6k
Forks
3.5k
Avg merge
3d 2h
Merged PRs (30d)
60

Description

### Describe the bug

The Graph REST API has a limit of 100 entries per page. If one wants to fetch more records than that, there is a `@odata.nextLink` optional property in the API response to keep fetching in a loop. If I try to make a simple loop using `@odata.nextLink`, an infinite loop is created, because after the second page, the URL is malformed and it gets stuck on the second page.

### Related command

`az rest -u "https://graph.microsoft.com/v1.0/servicePrincipals"`

### Errors

Infinite loop due to pagination

### Issue script & Debug output

I am running the following command:

```bash
az rest -u "https://graph.microsoft.com/v1.0/servicePrincipals"
```

e.g.:

```bash
az rest -u "https://graph.microsoft.com/v1.0/servicePrincipals"

# output is fine, we take @odata.nextLink and call it again

az rest -u "https://graph.microsoft.com/v1.0/servicePrincipals?$skiptoken=RFNwdAIAAQAAADVTZ...redacted"

# we get output, but now the @odata.nextLink is malformed:

az rest -u "https://graph.microsoft.com/v1.0/servicePrincipals?=RFNwdAIAAQAAADVTZXJ2aWNl...-->this_shouldnt_be_here<--&$skiptoken=RFNwdAIAAQAAADVTZXJ2aW...actual_token"

# this will now only return the second page forever, and the @odata.nextLink will keep getting larger and larger
```

### Expected behavior

`@odata.nextLink` should not cause infinite loops

### Environment Summary
```bash
azure-cli 2.77.0

core 2.77.0
telemetry 1.1.0

Extensions:
rdbms-connect 1.0.6

Dependencies:
msal 1.34.0b1
azure-mgmt-resource 23.3.0

Python location '/opt/az/bin/python3'
Config directory '/home/octavian/.azure'
Extensions directory '/home/octavian/.azure/cliextensions'

Python (Linux) 3.13.7 (main, Aug 26 2025, 08:47:13) [GCC 12.2.0]

Legal docs and information: aka.ms/AzureCliLegal

Your CLI is up-to-date.
```
### Additional context

I was able to fix this by manually constructing the URL:

```ts
export async function fetchFromGraphApiWithPagination(
url: string,
options?: Omit & Omit,
): Promise {
const output: T[] = [];
let targetUrl = url;

while (true) {
const result = await executeCommand(`az rest -u "${targetUrl}"`, {
...options,
parseJson: true,
});

if (result?.value && Array.isArray(result.value)) {
output.push(...result.value);
}
// Manually handle skip token because Azure nextLinks are glitched and will infinite loop otherwise
if (result?.['@odata.nextLink']) {
const nextLink = new URL(result['@odata.nextLink']);
const skipToken = nextLink.searchParams.get('$skiptoken');
if (!skipToken) {
clack.log.error(
`ERROR: Azure Graph REST API pagination is glitching out.\nNext URL is missing skip token.\nRecord fetching cancelled to prevent infinite loop.\nYou will likely be missing some records.`,
);
break;
} else {
const newUrl = new URL(url);
newUrl.searchParams.set('$skiptoken', skipToken);
targetUrl = newUrl.toString();
}
} else {
break;
}
}
return output;
}
```

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.