dmtrKovalenko/fff · error · Error

patterns array must have at least 1 element

Error message

patterns array must have at least 1 element

What it means

multiGrep requires at least one pattern; the tool validates `params.patterns?.length` and throws when the array is missing, null, or empty. This is an explicit input validation guard before hitting the native grep.

Solutions

  1. Pass at least one literal pattern in the patterns array
  2. If all patterns were filtered out, skip the call entirely instead of invoking with []
  3. Use the single-pattern grep tool when you only have one pattern
  4. Validate the array length before calling when patterns are generated dynamically

Example fix

// before
await multiGrep.execute(id, { patterns: filteredPatterns }); // [] when nothing matched

// after
if (filteredPatterns.length > 0) {
  await multiGrep.execute(id, { patterns: filteredPatterns });
}
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(patterns) || patterns.length === 0) throw new Error('patterns must contain at least 1 element');

Type guard

const hasPatterns = (p: unknown): p is { patterns: [string, ...string[]] } =>
  typeof p === 'object' && p !== null && Array.isArray((p as any).patterns) && (p as any).patterns.length > 0;

Try / catch

try { await multiGrepTool.execute(id, params, signal); } catch (e) { if (String(e).includes('at least 1 element')) return null; throw e; }

Prevention

When it happens

Trigger: Calling multiGrep with `patterns: []`, with `patterns` omitted, or with `patterns: null` (e.g. spread-built param objects that collapsed to empty).

Common situations: Dynamically generating pattern lists where all candidates were filtered out; LLM/agent emitting an empty array; template code leaving the patterns slot unfilled.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of dmtrKovalenko/fff@7f8537e70f (2026-09-10). Data as JSON: /api/errors/46d3a48015ebdb09. Report an issue: GitHub.

Appendix: source

Thrown at packages/pi-fff/src/index.ts:1199

      ),
      cursor: Type.Optional(Type.String({ description: "Pagination cursor" })),
    });

    queueTool(() => toolNames.multiGrep, {
      description:
        "Search file contents for ANY of multiple literal patterns (OR, SIMD Aho-Corasick). Faster than regex alternation.",
      promptSnippet: "Multi-pattern OR content search",
      promptGuidelines: (names) => [
        `${names.multiGrep}: use when searching for several identifiers at once.`,
        `${names.multiGrep}: include all naming-convention variants (snake/camel/Pascal).`,
        `${names.multiGrep}: patterns are literal. Use constraints for file filters.`,
      ],
      parameters: multiGrepSchema,

      async execute(_toolCallId, params, signal) {
        if (signal?.aborted) throw new Error("Operation aborted");
        if (!params.patterns?.length)
          throw new Error("patterns array must have at least 1 element");

        const f = await ensureFinder(activeCwd);
        const effectiveLimit = Math.max(1, params.limit ?? DEFAULT_GREP_LIMIT);
        const pageSize = Math.min(effectiveLimit, GREP_PAGE_SIZE_MAX);
        const context = clampContext(params.context);

        const grepResult = f.multiGrep({
          patterns: params.patterns,
          constraints: params.constraints,
          maxMatchesPerFile: GREP_MAX_MATCHES_PER_FILE,
          pageSize,
          smartCase: true,
          cursor: (params.cursor ? getCursor(params.cursor) : null) ?? null,
          beforeContext: context,
          afterContext: context,
        });

        if (!grepResult.ok) throw new Error(grepResult.error);

View on GitHub (pinned to 7f8537e70f)