Back to skills
Error Pattern Safety
Error Pattern Safety Guidelines for Agentic Engines
271 stars
0 votes
0 copies
0 views
Added 12/19/2025
developmentjavascriptgojavaexpresstesting
Install via CLI
$
openskills install githubnext/gh-awFiles
SKILL.md
---
name: error-pattern-safety
description: Error Pattern Safety Guidelines for Agentic Engines
---
# Error Pattern Safety Guidelines
This document outlines the safety guidelines for error pattern regex in agentic engines to prevent infinite loops in JavaScript.
## The Problem
When using regex patterns with the JavaScript global flag (`/pattern/g`), patterns that can match zero-width (empty strings) can cause infinite loops. This happens because:
1. JavaScript's `regex.exec()` with the `g` flag uses `lastIndex` to track position
2. When a pattern matches zero-width, `lastIndex` doesn't advance
3. The same position is matched repeatedly, causing an infinite loop
## Dangerous Pattern Examples
**❌ NEVER USE THESE PATTERNS:**
```javascript
// Pure .* - matches everything including empty string at end
/.*/g
// Single character with * - matches zero or more (including zero)
/a*/g
// Patterns that can match empty string
/(x|y)*/g
```
## Safe Pattern Examples
**✅ ALWAYS USE PATTERNS LIKE THESE:**
```javascript
// Required prefix before .*
/error.*/gi
/error.*permission.*denied/gi
// Specific structure with required content
/\[(\d{4}-\d{2}-\d{2})\]\s+(ERROR):\s+(.+)/g
// Required characters throughout
/access denied.*user.*not authorized/gi
```
## Pattern Safety Rules
1. **Always require at least one character match**
- Use `.+` instead of `.*` when you need "something"
- Ensure pattern has required prefix/suffix
2. **Never use bare `.*` as the entire pattern**
- Always combine with required text: `error.*`
- Never just `.*` or `.*?`
3. **Test patterns against empty string**
```javascript
const regex = /your-pattern/g;
if (regex.test("")) {
throw new Error("Pattern matches empty string - DANGEROUS!");
}
```
4. **Use specific anchors when possible**
- Start: `^error.*`
- End: `.*error$`
- Word boundaries: `\berror\b`
## Validation Tests
All error patterns must pass these tests:
### Go Tests (pkg/workflow/engine_error_patterns_infinite_loop_test.go)
```go
// Test that pattern doesn't match empty string
func TestPatternSafety(t *testing.T) {
pattern := "your-pattern"
regex := regexp.MustCompile(pattern)
if regex.MatchString("") {
t.Error("Pattern matches empty string!")
}
}
```
### JavaScript Tests (pkg/workflow/js/validate_errors.test.cjs)
```javascript
test("should not match empty string", () => {
const regex = new RegExp("your-pattern", "g");
expect(regex.test("")).toBe(false);
});
```
## Safety Mechanisms in validate_errors.cjs
The `validate_errors.cjs` script has built-in protections:
1. **Zero-width detection**: Checks if `regex.lastIndex` stops advancing
2. **Iteration warning**: Warns at 1000 iterations
3. **Hard limit**: Stops at 10,000 iterations to prevent hang
```javascript
// Safety check in validate_errors.cjs
if (regex.lastIndex === lastIndex) {
core.error(`Infinite loop detected! Pattern: ${pattern.pattern}`);
break;
}
```
## Adding New Error Patterns
When adding new error patterns to engines:
1. **Write the pattern with required content**
```go
{
Pattern: `(?i)error.*permission.*denied`,
LevelGroup: 0,
MessageGroup: 0,
Description: "Permission denied error",
}
```
2. **Test against empty string**
- Run: `make test-unit`
- Checks: `TestAllEnginePatternsSafe`
3. **Test with actual log samples**
- Ensure it matches real errors
- Ensure it doesn't match informational text
4. **Document the pattern**
- Add clear description
- Note what it's designed to catch
## Pattern Conversion: Go to JavaScript
Patterns are converted from Go to JavaScript:
```go
// Go pattern (case-insensitive flag)
Pattern: `(?i)error.*permission.*denied`
// Converted to JavaScript
new RegExp("error.*permission.*denied", "gi")
```
The `(?i)` prefix is removed because JavaScript uses the `i` flag instead.
## Examples from Current Codebase
### ✅ Safe Patterns
```go
// Requires "error" prefix
Pattern: `(?i)error.*permission.*denied`
// Requires specific timestamp format
Pattern: `(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[(ERROR)\]\s+(.+)`
// Requires "access denied" prefix
Pattern: `(?i)access denied.*user.*not authorized`
```
### How to Fix Unsafe Patterns
If you find a pattern that matches empty string:
**Before (unsafe):**
```go
Pattern: `.*error.*` // Can match empty at start/end
```
**After (safe):**
```go
Pattern: `error.*` // Requires "error" at start
// OR
Pattern: `.*error.+` // Requires "error" and at least one char after
// OR
Pattern: `\berror\b.*` // Requires word "error"
```
## Testing Checklist
Before committing pattern changes:
- [ ] Run `make test-unit`
- [ ] Check `TestAllEnginePatternsSafe` passes
- [ ] Check `TestErrorPatternsNoInfiniteLoopPotential` passes
- [ ] Run JavaScript tests: `cd pkg/workflow/js && npm test`
- [ ] Verify pattern matches intended error messages
- [ ] Verify pattern doesn't match informational text
## References
- Go regex syntax: https://pkg.go.dev/regexp/syntax
- JavaScript regex: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
- Test files:
- `pkg/workflow/engine_error_patterns_infinite_loop_test.go`
- `pkg/workflow/js/validate_errors.test.cjs`
- `pkg/workflow/error_pattern_tuning_test.go`
Attribution
Comments (0)
No comments yet. Be the first to comment!
