can1357/oh-my-pi · error

Operation ${operationNumber} has an empty pattern.

Error message

Operation ${operationNumber} has an empty pattern.

What it means

parsePattern validates each operation's MATCH text. An operation whose pattern is blank (only whitespace) after the « opener carries no information about what to replace, so it is rejected with the operation number. A sibling error ("has no visible current text") covers patterns whose characters are all stripped by normalization. validateSelectionMarkers then checks ⟪...⟫ selection markers.

Source

Thrown at packages/coding-agent/src/edit/sloppy.ts:1479

				starts.push(index);
				ends.push(next);
			}
		}
		index = next;
	}
	return { text, starts, ends };
}

function patternGapAt(source: string, offset: number): string | undefined {
	return source.startsWith(GAP, offset) ? GAP : undefined;
}

function patternContainsGap(source: string): boolean {
	return source.includes(GAP);
}

function parsePattern(pattern: string, operationNumber: number): ParsedPattern {
	if (pattern.trim() === "") throw new Error(`Operation ${operationNumber} has an empty pattern.`);
	validateSelectionMarkers(pattern, operationNumber);
	const hasGap = patternContainsGap(pattern);
	const hasSelection = pattern.includes(SELECT_OPEN);
	if (!hasGap && !hasSelection) {
		const normalized = normalizeText(pattern).text;
		if (normalized === "") throw new Error(`Operation ${operationNumber} has no visible current text.`);
		return {
			tokens: [{ kind: "literal", text: pattern, normalized }],
			selectionStart: 0,
			selectionEnd: 1,
			insertion: false,
			lineInsertion: false,
			selectedCaptureIndices: [],
			selectionRanges: [],
			selectionPairs: [],
			literalFallback: undefined,
		};
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Put the exact current text to be replaced between « and » — the pattern must have non-whitespace content.
  2. For an insertion, include the anchor line before the insertion point as the pattern and emit anchor+new text in the rewrite.
  3. Check the payload wasn't truncated or stripped of its pattern lines between generation and apply.

Example fix

// before
«
»
new text

// after
«
anchor line
»
anchor line
new text
Defensive patterns

Strategy: validation

Validate before calling

// per-operation: pattern must contain visible text
const ops = body.split(/^«\*?$/m).slice(1);
for (let i = 0; i < ops.length; i++) {
  const pattern = ops[i].split(/^»/m)[0];
  if (pattern.trim() === "") throw new Error(`operation ${i + 1} has an empty pattern`);
}

Type guard

const hasVisiblePattern = (op: string): boolean => op.split(/^»/m)[0].trim() !== "";

Try / catch

catch (err) {
  if (err instanceof Error && err.message.includes("has an empty pattern")) {
    // regenerate the operation with an anchored match block
  }
}

Prevention

When it happens

Trigger: A payload with « followed immediately by » (empty match), or a match block containing only spaces/tabs/newlines; also occurs when a model emits the opener and separator back-to-back intending an insertion-only edit.

Common situations: Models attempting pure insertions with an empty MATCH block; truncated payloads where pattern lines were lost; whitespace-only bodies after copy-paste; using this format for file creation instead of the proper add mechanism.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/b2fb075741d8c89d. Report an issue: GitHub.