cloudflare / cloudflare/cloudflare-typescript
AI Gateway logs.list() filters parameter is silently ignored due to qs serialization with arrayFormat: 'repeat'
- Dominant language
- TypeScript
- Stars
- 814
- Forks
- 190
- Avg merge
- 1h 38m
- Merged PRs (30d)
- 2
Description
## Description
The `client.aiGateway.logs.list()` method accepts a typed `filters` parameter (`Array`), but the filters are silently ignored by the API because `stringifyQuery` serializes them in a format the API doesn't understand.
## Root cause
The Cloudflare SDK overrides `stringifyQuery` in `src/index.ts:480`:
```ts
protected override stringifyQuery(query: Record): string {
return qs.stringify(query, { allowDots: true, arrayFormat: 'repeat' });
}
```
With `arrayFormat: 'repeat'` and `allowDots: true`, an array of filter objects like:
```ts
filters: [
{ key: "metadata.key", operator: "eq", value: ["requestId"] },
{ key: "metadata.value", operator: "eq", value: ["abc-123"] },
]
```
Gets serialized as:
```
filters.key=metadata.key&filters.operator=eq&filters.value=requestId&filters.key=metadata.value&filters.operator=eq&filters.value=abc-123
```
This flat serialization **loses the array structure** — the API can't determine which `key` belongs to which `operator`/`value`. The result is the API ignoring the filters entirely and returning all logs.
The correct format (which works when using `fetch` directly) is JSON-encoded:
```
filters=%5B%7B%22key%22%3A%22metadata.key%22%2C%22operator%22%3A%22eq%22%2C%22value%22%3A%5B%22requestId%22%5D%7D%2C...%5D
```
i.e. `filters=[{"key":"metadata.key","operator":"eq","value":["requestId"]},...]`
## Reproduction
```ts
import Cloudflare from "cloudflare";
const client = new Cloudflare({ apiToken: "..." });
const logs = [];
for await (const log of client.aiGateway.logs.list("my-gateway", {
account_id: "...",
filters: [
{ key: "metadata.key", operator: "eq", value: ["requestId"] },
{ key: "metadata.value", operator: "eq", value: ["some-uuid"] },
],
})) {
logs.push(log);
}
console.log(logs.length);
// Expected: 1 (only matching logs)
// Actual: ALL logs in the gateway (filters ignored)
```
## Workaround
Use `fetch` directly with JSON-encoded filters:
```ts
const filters = JSON.stringify([
{ key: "metadata.key", operator: "eq", value: ["requestId"] },
{ key: "metadata.value", operator: "eq", value: [requestId] },
]);
const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai-gateway/gateways/${gatewayId}/logs?filters=${encodeURIComponent(filters)}`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${apiToken}` },
});
```
## Affected methods
This likely affects any method using the `filters` query parameter with arrays of objects:
- `client.aiGateway.logs.list()`
- `client.aiGateway.logs.delete()`
- `client.aiGateway.datasets.list()` (if it uses the same filter format)
## Environment
- SDK version: `cloudflare@5.2.0`
- Runtime: Cloudflare Workers (also reproducible in Node.js)
Contributor guide
Assessment
This issue has not been assessed yet.