Skip to content

AI Gateway logs.list() filters parameter is silently ignored due to qs serialization with arrayFormat: 'repeat' #2723

@tecoad

Description

@tecoad

Description

The client.aiGateway.logs.list() method accepts a typed filters parameter (Array<LogListParams.Filter>), 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:

protected override stringifyQuery(query: Record<string, unknown>): string {
    return qs.stringify(query, { allowDots: true, arrayFormat: 'repeat' });
}

With arrayFormat: 'repeat' and allowDots: true, an array of filter objects like:

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

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:

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions