makeplane/plane · error · Error

AND group must contain at least one condition

Error message

AND group must contain at least one condition

What it means

Thrown while converting an external filter expression shaped as an AND group: the adapter looks up expression[LOGICAL_OPERATOR.AND] and requires it to be a non-empty array. An AND key whose value is [] or not an array (string, object) is rejected because an empty logical group has no semantics in the internal TFilterExpression tree.

Source

Thrown at packages/shared-state/src/store/work-item-filters/adapter.ts:77

      }

      const [property, operator, value] = conditionResult;
      return createConditionNode({
        property,
        operator,
        value,
      });
    }

    // It's a logical group - check which type
    const expressionKeys = Object.keys(expression);

    if (LOGICAL_OPERATOR.AND in expression) {
      const andExpression = expression as { [LOGICAL_OPERATOR.AND]: TWorkItemFilterExpressionData[] };
      const andConditions = andExpression[LOGICAL_OPERATOR.AND];

      if (!Array.isArray(andConditions) || andConditions.length === 0) {
        throw new Error("AND group must contain at least one condition");
      }

      const convertedConditions = andConditions.map((item) => this._convertExpressionToInternal(item));
      return createAndGroupNode(convertedConditions);
    }

    throw new Error(`Invalid expression: unknown structure with keys [${expressionKeys.join(", ")}]`);
  }

  /**
   * Converts internal filter expression to external format
   * @param internalFilter - The internal filter expression
   * @returns External filter expression
   */
  toExternal(internalFilter: TFilterExpression<TWorkItemFilterProperty>): TWorkItemFilterExpression {
    if (!internalFilter) {
      return {};
    }

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Normalize on save: if an AND group has zero children, prune the group (or skip persisting it) before serialization.
  2. On load, sanitize the payload by collapsing empty AND groups to an empty/no-filter state.
  3. Fix the UI to prevent saving a group with no conditions.

Example fix

// before
const saved = JSON.stringify(filterTree);

// after
function pruneEmptyGroups(node) {
  if (node && typeof node === 'object' && Array.isArray(node.AND)) {
    const kids = node.AND.map(pruneEmptyGroups).filter(Boolean);
    return kids.length ? { AND: kids } : undefined;
  }
  return node;
}
const saved = JSON.stringify(pruneEmptyGroups(filterTree) ?? {});
Defensive patterns

Strategy: validation

Validate before calling

function normalizeAndGroup(node: any): any {
  if (node && Array.isArray(node.AND)) {
    const kids = node.AND.map(normalizeAndGroup).filter(Boolean);
    if (kids.length === 0) return undefined;
    return { AND: kids };
  }
  return node;
}

Type guard

function isNonEmptyAndGroup(e: any): boolean {
  return e && Array.isArray(e.AND) && e.AND.length > 0;
}

Try / catch

try { adapter.toInternal(expr); } catch (e) {
  if (/AND group must contain/.test((e as Error).message)) { expr = {}; /* retry as no-filter */ } else throw e;
}

Prevention

When it happens

Trigger: Persisted payload like { AND: [] }; a UI that allows adding an AND group without children and then saves; corrupted/migrated data where the conditions array got stripped.

Common situations: User adds a group, removes all conditions, and the autosave writes { AND: [] }; import/migration tool that drops nested condition keys.

Related errors


AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12). Data as JSON: /api/errors/ee8ee15c767e5454. Report an issue: GitHub.