{"record":{"id":"670d4a9c2d6707d3","repo":"actualbudget/actual","slug":"conditions-are-required","errorCode":null,"errorMessage":"Conditions are required","messagePattern":"Conditions are required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/filters/app.ts","lineNumber":138,"sourceCode":"\n  if (item.name) {\n    if (await filterNameExists(item.name, item.id, true)) {\n      throw new Error('There is already a filter named ' + item.name);\n    }\n  } else {\n    throw new Error('Filter name is required');\n  }\n\n  if (item.conditions.length > 0) {\n    const condExists = conditionExists(item, filter.filters, true);\n    if (condExists) {\n      throw new Error(\n        'Duplicate filter warning: conditions already exist. Filter name: ' +\n          condExists,\n      );\n    }\n  } else {\n    throw new Error('Conditions are required');\n  }\n\n  // Create the filter here based on the info\n  await db.insertWithSchema('transaction_filters', filterModel.fromJS(item));\n\n  return filterId;\n}\n\nasync function updateFilter(filter) {\n  const item = {\n    id: filter.state.id,\n    conditions: filter.state.conditions,\n    conditionsOp: filter.state.conditionsOp,\n    name: filter.state.name,\n  };\n  if (item.name) {\n    if (await filterNameExists(item.name, item.id, false)) {\n      throw new Error('There is already a filter named ' + item.name);","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/filters/app.ts#L120-L156","documentation":"createFilter requires at least one condition. If filter.state.conditions is an empty array (length 0), the else branch throws 'Conditions are required'. A saved filter with no conditions would match nothing and is considered invalid.","triggerScenarios":"Calling filter-create with state.conditions = []; a UI allowing the save button while the condition builder is empty; a script constructing a filter payload with an unpopulated conditions array.","commonSituations":"Custom frontends on the Actual API that don't enforce at least one rule row; bulk-import tooling writing filters with placeholder empty conditions; race where conditions are cleared before submit.","solutions":["Ensure state.conditions contains at least one condition object ({field, op, value, options}) before calling createFilter.","Validate conditions.length > 0 client-side and disable save until a condition is added.","Catch the error and surface 'add a condition' guidance to the user."],"exampleFix":"// before\nawait aql.query('filter-create', { state: { name: 'My filter', conditions: [], conditionsOp: 'and' } });\n// after\nconst conditions = [{ field: 'amount', op: 'gt', value: 100, options: [] }];\nif (conditions.length === 0) throw new Error('Add at least one condition');\nawait aql.query('filter-create', { state: { name: 'My filter', conditions, conditionsOp: 'and' } });","handlingStrategy":"validation","validationCode":"if (!Array.isArray(state.conditions) || state.conditions.length === 0) {\n  throw new Error('At least one condition is required');\n}","typeGuard":"function hasConditions(state: { conditions?: unknown[] }): state is { conditions: [unknown, ...unknown[]] } {\n  return Array.isArray(state.conditions) && state.conditions.length > 0;\n}","tryCatchPattern":"try {\n  await aql.query('filter-create', { state });\n} catch (e) {\n  if (e.message === 'Conditions are required') {\n    // guide the user to add a condition\n  } else throw e;\n}","preventionTips":["Require at least one condition row before enabling save","In scripts, never pass conditions: [] as a placeholder","Validate condition objects have field/op/value set"],"tags":["filters","validation","empty-array","api"],"backgroundTag":"missing-required-field","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}