# eth_getLogs block range limits and chunked queries

> Original page: https://docs.blockvectra.com/en/guides/getlogs-block-range/

## eth\_getLogs block range limits [#eth_getlogs-block-range-limits]

When calling the JSON-RPC `eth_getLogs` method, the block span of a single request is calculated as `toBlock − fromBlock + 1` and cannot exceed the target chain's published `max_logs_block_range`.

This limit varies by chain. Per-chain parameters are published through the public endpoint `GET /v1/chains` (chains are listed on [Supported Chains](/en/chains/)). This endpoint is unauthenticated, unbilled, and unmetered. When developing client applications, query this endpoint dynamically at runtime rather than hardcoding block range limits into your code.

According to the specification, filter fields `fromBlock` and `toBlock` follow these rules:

* **Defaults and null**: When `fromBlock` or `toBlock` is omitted or `null`, it defaults to `latest`.
* **Tag resolution**: Named tags such as `latest` are resolved using the service's most recently polled block height.
* **Unchecked conditions**: Filters specifying `blockHash`, values that cannot be parsed, and intervals where `toBlock < fromBlock` are not checked for span and are forwarded to the node for handling.

## Exceeding the block span limit [#exceeding-the-block-span-limit]

When a single request's block span `toBlock − fromBlock + 1` exceeds the chain's `max_logs_block_range`, the service rejects the request with HTTP 200 and a JSON-RPC error:

* **Error code**: `-32602`
* **Error message**: `eth_getLogs block range too large: max <N> blocks`
* **Billing status**: This rejection is generated by the service itself and is **not billed** (`billed: false`).

### Specification example request [#specification-example-request]

Below is the example request from the specification exceeding the span limit (`reqLogsTooWide`):

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "eth_getLogs",
  "params": [
    {
      "fromBlock": "0x45a2409",
      "toBlock": "0x45a27f1"
    }
  ]
}
```

### Specification example response [#specification-example-response]

The corresponding error response example from the specification (`errLogsRangeTooLarge`):

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "eth_getLogs block range too large: max <N> blocks"
  }
}
```

Where `<N>` is the target chain's `max_logs_block_range` (published via `GET /v1/chains`).

In a batch request containing multiple calls, if an `eth_getLogs` call exceeds the block span limit, that specific item returns the `-32602` error above and is not billed.

## Performing chunked queries [#performing-chunked-queries]

To query logs over a large block interval, first query the target chain's `max_logs_block_range`, divide the target interval into contiguous chunks of `[from, from + max - 1]`, and send sequential requests while aggregating the results.

The following examples use `robinhood_mainnet` to demonstrate chunked queries:

<Tabs groupId="code-lang" items="['cURL', 'TypeScript', 'Python']">
  <Tab value="cURL">
    ```bash
    export BLOCKVECTRA_API_KEY="rgw_your_api_key"

    # 1. Read max_logs_block_range from the public chains endpoint (unauthenticated, unbilled)
    curl -s "https://dev-api.blockvectra.network/v1/chains"

    # 2. Make a single compliant request within the chain's max_logs_block_range (toBlock - fromBlock + 1)
    curl -s "https://dev-api.blockvectra.network/v1/robinhood_mainnet" \
      -H 'Content-Type: application/json' \
      -H "x-api-key: $BLOCKVECTRA_API_KEY" \
      -d '{
        "jsonrpc": "2.0",
        "id": 1,
        "method": "eth_getLogs",
        "params": [{
          "address": "0x1111111111111111111111111111111111111111",
          "fromBlock": "0x45a2409",
          "toBlock": "0x45a246c"
        }]
      }'
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    const CHAIN = "robinhood_mainnet";
    const RPC_ENDPOINT = "https://dev-api.blockvectra.network/v1/robinhood_mainnet";

    // 1. Fetch max_logs_block_range from the public GET /v1/chains endpoint (unauthenticated, unbilled)
    const chainsUrl = new URL("/v1/chains", RPC_ENDPOINT);
    const chainsRes = await fetch(chainsUrl);
    const { chains } = (await chainsRes.json()) as {
      chains: Array<{ chain: string; max_logs_block_range: number }>;
    };

    const targetChain = chains.find((c) => c.chain === CHAIN);
    if (!targetChain) {
      throw new Error(`Chain ${CHAIN} not found`);
    }

    const maxRange = targetChain.max_logs_block_range;

    // 2. Query chunks sequentially over [from, from + max - 1] and aggregate results (both endpoints inclusive)
    const fromBlock = 0x45a2409;
    const toBlock = 0x45a2900;

    const allLogs: unknown[] = [];
    let cur = fromBlock;

    while (cur <= toBlock) {
      const chunkEnd = Math.min(cur + maxRange - 1, toBlock);

      const res = await fetch(RPC_ENDPOINT, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": process.env.BLOCKVECTRA_API_KEY!,
        },
        body: JSON.stringify({
          jsonrpc: "2.0",
          id: 1,
          method: "eth_getLogs",
          params: [
            {
              address: "0x1111111111111111111111111111111111111111",
              fromBlock: "0x" + cur.toString(16),
              toBlock: "0x" + chunkEnd.toString(16),
            },
          ],
        }),
      });

      const body = (await res.json()) as {
        result?: unknown[];
        error?: { code: number; message: string };
      };

      if (body.error) {
        throw new Error(`eth_getLogs error ${body.error.code}: ${body.error.message}`);
      }

      if (body.result) {
        allLogs.push(...body.result);
      }

      cur = chunkEnd + 1;
    }

    console.log(`Fetched ${allLogs.length} logs across blocks`);

    // npx tsx example.mts
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    from urllib.parse import urljoin
    import requests

    CHAIN = "robinhood_mainnet"
    RPC_ENDPOINT = "https://dev-api.blockvectra.network/v1/robinhood_mainnet"

    # 1. Fetch max_logs_block_range from the public GET /v1/chains endpoint (unauthenticated, unbilled)
    chains_url = urljoin(RPC_ENDPOINT, "/v1/chains")
    chains_res = requests.get(chains_url)
    chains_res.raise_for_status()

    chains = chains_res.json().get("chains", [])
    target_chain = next((c for c in chains if c["chain"] == CHAIN), None)
    if not target_chain:
        raise RuntimeError(f"Chain {CHAIN} not found")

    max_range = target_chain["max_logs_block_range"]

    # 2. Query chunks sequentially over [from, from + max - 1] and aggregate results (both endpoints inclusive)
    from_block = 0x45a2409
    to_block = 0x45a2900

    all_logs: list = []
    cur = from_block

    while cur <= to_block:
        chunk_end = min(cur + max_range - 1, to_block)

        res = requests.post(
            RPC_ENDPOINT,
            headers={
                "Content-Type": "application/json",
                "x-api-key": os.environ["BLOCKVECTRA_API_KEY"],
            },
            json={
                "jsonrpc": "2.0",
                "id": 1,
                "method": "eth_getLogs",
                "params": [
                    {
                        "address": "0x1111111111111111111111111111111111111111",
                        "fromBlock": hex(cur),
                        "toBlock": hex(chunk_end),
                    }
                ],
            },
        )
        res.raise_for_status()
        body = res.json()

        if "error" in body:
            err = body["error"]
            raise RuntimeError(f"eth_getLogs error {err.get('code')}: {err.get('message')}")

        all_logs.extend(body.get("result", []))
        cur = chunk_end + 1

    print(f"Fetched {len(all_logs)} logs across blocks")
    ```
  </Tab>
</Tabs>

## Batch request considerations [#batch-request-considerations]

If you consider packing multiple chunked queries into a single JSON-RPC batch request, keep the batch and burst capacity rules in mind:

* **Batch size limit**: Batch requests accept 1 to 100 calls. Submitting more than 100 calls is rejected with HTTP 200 and error code `-32600 batch too large: max 100 calls` (not billed).
* **Single-request burst capacity**: Upon arrival, the service pre-deducts the sum of full weights for calls in the request. If the sum of full weights within a single request exceeds the key's burst capacity, the service immediately returns HTTP 429 with error code `-32022 request cost <N> CU exceeds burst capacity <M> CU` (not billed). Waiting will not succeed; the request must be split into smaller batches.
* **Insufficient bucket capacity**: If the sum of full weights does not exceed burst capacity but the token bucket lacks enough available capacity, the service returns HTTP 429 with error code `-32005 rate limit exceeded` and `Retry-After`; see [What is not billed: error codes and billing rules](/en/guides/billing-rules/) for retry and billing details.

Therefore, when performing large-scale log queries, sequential chunked queries are recommended; if batching, keep the number of calls per batch small enough so the sum of full weights remains within the burst capacity.

## Related guides and billing rules [#related-guides-and-billing-rules]

* For a comparison between `eth_getLogs` and the Data API transfers endpoints (address transfers and token transfers), including coverage and finality differences, see [Recent node data vs indexed history: when to use eth\_getLogs and when to use the transfers API](/en/guides/logs-vs-transfers/).
* For full details on compute units (CU), hourly settlement, and non-billed error responses, see [What is not billed: error codes and billing rules](/en/guides/billing-rules/).

## Next steps [#next-steps]

* [Browse the datasets directory](https://blockvectra.com/en/data/) to see every dataset BlockVectra indexes.
* [See the free plan and pricing](https://blockvectra.com/en/pricing/#free) to check what your account includes.
* [Log in to the console](https://console.blockvectra.com/en/login/?next=%2Fen%2Fkeys%2F) to create an API key.
