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

  1. Give every regex rule a unique, non-blank Name before calling Payload.
  2. If rules come from config, validate names at load time (non-empty, unique) with a line-numbered error instead of failing at redaction time.
  3. 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

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


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/ce82ca3aa25e4bb0. Report an issue: GitHub.