JuliusBrussee/caveman · error · ErrInvalidRule
%w: empty name
Error message
%w: empty name
What it means
A regex rule reached the name/pattern validation with a Name that is empty or only whitespace (TrimSpace(name) == ""). Names are load-bearing here: the default replacement placeholder is '[REDACTED:<name>]' and the rule fingerprint/report identify rules by name, so an unnamed rule cannot be audited or distinguished in the RedactionReport.
Source
Thrown at shared/platform/redact/payload.go:579
sb.WriteString(r.Pattern)
sb.WriteByte('\x1f')
sb.WriteString(r.Replacement)
sb.WriteByte('\x1e')
switch r.Type {
case RuleTypeBuiltin:
// A reference to the unconditional floor. Nothing to run, and
// nothing it could switch off.
continue
case RuleTypeRegex:
case RuleTypeJSONPath, RuleTypeHeader:
return nil, "", fmt.Errorf("%w: %q (rule %q)", ErrRuleUnsupported, r.Type, r.Name)
default:
return nil, "", fmt.Errorf("%w: %q (rule %q)", ErrRuleUnsupported, r.Type, r.Name)
}
if strings.TrimSpace(r.Name) == "" {
return nil, "", fmt.Errorf("%w: empty name", ErrInvalidRule)
}
if r.Pattern == "" {
return nil, "", fmt.Errorf("%w: rule %q has an empty pattern", ErrInvalidRule, r.Name)
}
re, err := regexp.Compile(r.Pattern)
if err != nil {
return nil, "", fmt.Errorf("%w: rule %q: %s", ErrInvalidRule, r.Name, err)
}
if re.MatchString("") {
// Such a pattern matches at every position and would replace the
// whole body with placeholders. Refuse it rather than destroy the
// capture.
return nil, "", fmt.Errorf("%w: rule %q matches the empty string", ErrInvalidRule, r.Name)
}
repl := r.Replacement
if repl == "" {
repl = "[REDACTED:" + r.Name + "]"
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Give every regex rule a unique, non-blank Name before calling Payload.
- If rules come from config, validate names at load time (non-empty, unique) with a line-numbered error instead of failing at redaction time.
- Add a struct-level check or linter/test over the rule set fixture.
Example fix
// before
rules := []redact.Rule{{Type: redact.RuleTypeRegex, Pattern: `Bearer [A-Za-z0-9._-]+`}} // no Name
// after
rules := []redact.Rule{{Name: "bearer-token", Type: redact.RuleTypeRegex, Pattern: `Bearer [A-Za-z0-9._-]+`}} Defensive patterns
Strategy: validation
Validate before calling
func validateRuleNames(rules []redact.Rule) error {
for _, r := range rules {
if r.Type == redact.RuleTypeRegex && strings.TrimSpace(r.Name) == "" {
return fmt.Errorf("regex rule with empty name (pattern %q)", r.Pattern)
}
}
return nil
} Type guard
func hasName(r redact.Rule) bool { return strings.TrimSpace(r.Name) != "" } Try / catch
if _, _, err := redact.Payload(body, rules); err != nil {
if errors.Is(err, redact.ErrInvalidRule) && strings.Contains(err.Error(), "empty name") {
// point the rule author at the offending entry
}
} Prevention
- Require non-empty unique names in the rules JSON Schema.
- Remember the name lands in '[REDACTED:<name>]' — make names self-documenting.
- Validate the rule set once at startup, not per capture.
When it happens
Trigger: compileOrgRules iterates a rule list where a RuleTypeRegex entry has Name: "" or " " — commonly from config where the name key was misspelled (label vs name), omitted, or a default struct was copied.
Common situations: YAML key mismatch (pattern present, name forgotten); programmatic rule construction that fills Pattern but never Name; refactors that renamed the Name field and left zero values.
Related errors
- %w: rule %q has an empty pattern
- cave_budget_denomination_ambiguous
- cave_budget_max_invalid
- cave_budget_output_floor_invalid
- cave_budget_on_exhausted_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/ce82ca3aa25e4bb0.
Report an issue: GitHub.