Configuring pfSense REST API Pagination for Large Offset Queries
0 reputation · 28 Jul 2023, 21:26 UTC
0 reputation · 28 Jul 2023, 21:26 UTC
Goal: Retrieve complete datasets from pfSense REST API endpoints (e.g., firewall rules) using the limit and offset parameters without losing records due to unexpected empty responses.
Uncertainty: In pfSense versions 2.6.0‑2.7.2, combining a very large offset (e.g., >100,000) with a small limit can cause the API to return an empty array instead of adjusting the offset or signaling an error, effectively hiding data beyond that threshold. It is unclear what offset range is safe for a given limit, whether a server‑side setting can modify this behavior, or if alternative pagination strategies (such as keyset pagination) are recommended.
Specific questions:
- What is the maximum offset value that guarantees a non‑empty page for a given limit size?
- Should client implementations treat an empty page as a signal to reduce the offset and retry, or is there a configurable API option to avoid this behavior?
- Is there a documented method to obtain accurate total counts or to use offset‑free pagination for large datasets in pfSense?
There is no documented "safe maximum offset" for the pfSense REST API, and no server-side setting that changes deep-offset behavior. The reliable fix is to stop depending on large offsets: cap your page size, sort on a stable field, and treat an empty page as "end of data," not as a signal to retry with a different offset. If you genuinely need to walk hundreds of thousands of records, use filtered queries, snapshots, or an export job instead of offset paging.
Confirmed, general behavior: offset pagination requires the server to count or skip every row before the requested page. Cost grows with the offset even when the page itself is tiny, and results can skip or duplicate rows when the underlying data (firewall states, logs, leases) changes between requests.
Likely, but not verified for your install: the empty-array-at-large-offset behavior you describe in 2.6.0–2.7.2 is most plausibly an internal guard or an integer/limit boundary in the REST package you are using, not a tunable. Which parameters exist at all (limit, offset, total, sort fields) depends on whether your API is the built-in REST capability or a community package such as pfSense-api, and on the endpoint. Do not assume uniform behavior across endpoints.
You can find the practical offset ceiling empirically with a binary search against a known data set:
curl -s -u admin:YOURPASS \
"https://pfsense.example/api/v1/firewall/rule?limit=100&offset=50000" \
| jq 'length'Double the offset until the response goes empty, then bisect. Compare latency at low and high offsets — a sharp slowdown before the empty page confirms the skip-cost explanation. Repeat while adding or removing a few rules to confirm whether pages shift. Note that any threshold you find this way is an observation about your version, not a guarantee; it can change across upgrades.
If the endpoint exposes a total count, treat it as approximate for live tables — it can go stale mid-walk and may itself be expensive to compute. Keyset (cursor) pagination — "give me rows where id > last_seen" — avoids the offset problem entirely, but only if your endpoint supports filtering and sorting on an indexed field. Check the endpoint documentation for your package; if it is not supported there, the snapshot approach above is the pragmatic substitute.
One detail that would sharpen this answer: which REST implementation you are running (built-in vs. a specific community package and version), since parameter names and limits differ between them.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 29 Jul 2023, 00:29 UTC
To add a technical layer to the discussion on empty responses: since pfSense REST implementations typically rely on PHP to slice datasets from the system configuration XML or internal databases, large offsets are not just computationally expensive—they are memory-intensive.
When a high offset is requested, the backend often loads a significant portion of the dataset into memory before discarding the preceding records to return the requested window. On low-resource hardware, this can trigger a PHP memory limit exhaustion or a request timeout. Depending on the specific API package version, these failures may be silently caught and returned as an empty array rather than a 500 Internal Server Error.
If you suspect memory exhaustion is causing the empty responses, monitor the pfSense Dashboard or run top via SSH while executing a high-offset query. A sharp spike in memory usage immediately preceding the empty response confirms a resource bottleneck rather than a logical API limit.