refinedev/refine · error · Error
Max deep reached
Error message
Max deep reached
What it means
Thrown by refine's Appwrite data provider when a CrudFilter logical operator chain (and/or/nested) exceeds the maximum recursion depth of 10 in generateFilter. It prevents infinite or pathological recursion while translating refine filters into Appwrite Query strings.
Source
Thrown at packages/appwrite/src/utils/generateFilter.ts:15
import type { CrudFilter } from "@refinedev/core";
import { Query } from "appwrite";
import { replaceIdWithAppwriteId } from "./replaceIdWithAppwriteId";
/**
* Generate a filter string for Appwrite from Refine's filter
* @param filter Refine's filter
* @param deep Max deep of the filter
* @returns Appwrite's filter string
*/
export const generateFilter = (filter: CrudFilter, deep = 10): string => {
const nextDeep = deep - 1;
if (nextDeep < 0) {
throw new Error("Max deep reached");
}
filter = replaceIdWithAppwriteId(filter);
switch (filter.operator) {
// Logical operators
case "eq":
return Query.equal(filter.field, filter.value);
case "ne":
return Query.notEqual(filter.field, filter.value);
case "gt":
return Query.greaterThan(filter.field, filter.value);
case "gte":
return Query.greaterThanEqual(filter.field, filter.value);
case "lt":
return Query.lessThan(filter.field, filter.value);
case "lte":
return Query.lessThanEqual(filter.field, filter.value);View on GitHub (pinned to 779d52a20e)
Solutions
- Flatten the filter tree so logical nesting stays under 10 levels (e.g. merge nested 'or' branches into one level)
- If filters are machine-generated, cap or simplify the generated structure before passing it to the data provider
- As a last resort, fork/patch generateFilter to raise the deep limit
Example fix
// before
const f = { operator: 'or', value: [{ operator: 'or', value: [{ operator: 'or', value: [/* ...deep... */] }] }] };
dataProvider.getList({ resource: 'posts', filters: [f] });
// after
const f = { operator: 'or', value: [cond1, cond2, cond3] }; // flattened, depth < 10
dataProvider.getList({ resource: 'posts', filters: [f] }); Defensive patterns
Strategy: validation
Validate before calling
const filterDepth = (f) => f.operator === 'and' || f.operator === 'or' ? 1 + Math.max(0, ...f.value.map(filterDepth)) : 0;
if (filterDepth(filter) >= 10) throw new Error('Filter too deep — flatten before sending');
await dataProvider.getList({ resource: 'posts', filters: [filter] }); Type guard
const isLogical = (f) => f.operator === 'and' || f.operator === 'or';
Try / catch
try { await dataProvider.getList({ resource, filters }); } catch (e) { if (e.message === 'Max deep reached') { /* flatten filters and retry */ } else throw e; } Prevention
- Flatten and/or chains when building filters programmatically
- Cap nesting depth in your own filter-builder UI
When it happens
Trigger: Passing a filter with more than 10 levels of nested logical operators (and/or) to the Appwrite data provider's getList, e.g. filter: { operator: 'or', value: [{ operator: 'or', value: [...10+ levels deep...] }] }.
Common situations: Programmatically generated filters (e.g. from a filter builder UI or a loop) that nest logical groups more than 10 levels; converting deeply nested filters from another data provider to Appwrite.
Related errors
- Value array must contain exactly two elements for "between"
- Operator ${filter.operator} is not supported
- 'getApiUrl' method is not implemented on refine-appwrite dat
- 'custom' method is not implemented on refine-appwrite data p
- Operator ${operator} is not supported for the Medusa data pr
AI-assisted analysis of refinedev/refine@779d52a20e (2026-08-27).
Data as JSON: /api/errors/09e7fd189c80a2de.
Report an issue: GitHub.