mastra-ai/mastra · error

RegexFilterProcessor requires at least one rule or preset

Error message

RegexFilterProcessor requires at least one rule or preset

What it means

RegexFilterProcessor applies regex-based filtering rules (with optional named presets) to text and streams. The constructor requires at least one rule, either via `rules` or via named `presets`; with none it would be a no-op processor, so it throws immediately at construction time. This fail-fast check prevents silently configuring a filter that does nothing.

Source

Thrown at packages/core/src/processors/processors/regex-filter.ts:323

  private phase: 'input' | 'output' | 'all';
  private includeRedactedValues: boolean;
  private streamCarryoverSize: number;

  /**
   * Invoked when the `redact` strategy rewrites a piece of text, once per
   * redacted message, message part, or stream chunk, with a
   * {@link RegexRedactionDetail} as `detail`. The `block` strategy reports
   * through the same callback, driven by the processor runner when it catches
   * the TripWire.
   */
  public onViolation?: (violation: ProcessorViolation) => void | Promise<void>;

  constructor(options: RegexFilterOptions) {
    const presetRules = (options.presets ?? []).flatMap(preset => PRESET_MAP[preset] ?? []);
    this.rules = [...presetRules, ...(options.rules ?? [])];

    if (this.rules.length === 0) {
      throw new Error('RegexFilterProcessor requires at least one rule or preset');
    }

    this.strategy = options.strategy ?? 'block';
    this.phase = options.phase ?? 'all';
    this.includeRedactedValues = options.includeRedactedValues ?? false;
    this.streamCarryoverSize = options.streamCarryoverSize ?? STREAM_CARRYOVER_SIZE;
    if (!Number.isSafeInteger(this.streamCarryoverSize) || this.streamCarryoverSize < 1) {
      throw new Error('RegexFilterProcessor streamCarryoverSize must be a positive safe integer');
    }
  }

  /**
   * Run every rule over the text and collect all matches, grouped by rule in
   * declaration order. Matches may overlap; callers that rewrite text must
   * de-overlap them first.
   */
  private collectMatches(text: string): RuleMatch[] {
    const matches: RuleMatch[] = [];

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Add at least one rule to `options.rules` (e.g. `{ pattern: /secret/i, replacement: '[REDACTED]' }`).
  2. Pass one or more valid preset names in `options.presets` (verify spelling against PRESET_MAP exports).
  3. Log/inspect the merged options object before construction to confirm rules or presets are non-empty.
  4. If rules are optional in your app, conditionally skip adding the processor instead of constructing it with none.

Example fix

// before
new RegexFilterProcessor({ presets: ['emailz'] });
// after
new RegexFilterProcessor({ presets: ['email'] });
// or
new RegexFilterProcessor({ rules: [{ pattern: /api[-_]?key/i, replacement: '[REDACTED]' }] });
Defensive patterns

Strategy: validation

Validate before calling

function assertRegexFilterOptions(o) {
  const presets = (o.presets ?? []).flatMap(p => PRESET_MAP[p] ?? []);
  if (presets.length + (o.rules?.length ?? 0) === 0) throw new TypeError('RegexFilterProcessor needs at least one rule or a valid preset');
}

Type guard

function hasRules(o): o is RegexFilterOptions & { rules: NonNullable<RegexFilterOptions['rules']> } {
  return Array.isArray(o.rules) && o.rules.length > 0;
}

Try / catch

try {
  const p = new RegexFilterProcessor(opts);
} catch (e) {
  if (e.message.includes('at least one rule or preset')) {
    console.error('Invalid filter config, using default rules', opts);
    p = new RegexFilterProcessor({ rules: DEFAULT_RULES });
  } else throw e;
}

Prevention

When it happens

Trigger: Constructing `new RegexFilterProcessor({})`, or passing `{ presets: [] }` and/or `{ rules: [] }` such that the merged rule array (preset rules plus custom rules) is empty. Also occurs when preset names are misspelled: `PRESET_MAP[preset] ?? []` silently yields no rules for unknown preset strings.

Common situations: Typos in preset names (e.g. `'emails'` instead of `'email'`), reading options from env/config that resolves to empty arrays, copying an example but removing the rules array, or building options dynamically so all rules get filtered out before construction.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/0993cdddfdcb5cf6. Report an issue: GitHub.