{"record":{"id":"b2bbbb255f643c5b","repo":"JuliusBrussee/caveman","slug":"redact-invalid-redaction-rule","errorCode":null,"errorMessage":"redact: invalid redaction rule","messagePattern":"redact: invalid redaction rule","errorType":"exception","errorClass":"ErrInvalidRule","httpStatus":null,"severity":"error","filePath":"shared/platform/redact/payload.go","lineNumber":72,"sourceCode":"\tRuleTypeJSONPath = \"json_path\"\n\tRuleTypeHeader   = \"header\"\n\tRuleTypeBuiltin  = \"builtin\"\n)\n\n// Origin values distinguish the built-in floor from operator-supplied rules in\n// the report.\nconst (\n\tOriginBuiltin = \"builtin\"\n\tOriginOrg     = \"org\"\n)\n\nvar (\n\t// ErrBodyTooLarge means the body exceeded MaxPayloadBytes.\n\tErrBodyTooLarge = errors.New(\"redact: payload exceeds redaction size limit\")\n\t// ErrInvalidRule means a rule could not be compiled or was structurally\n\t// unusable (empty name/pattern, or a pattern that matches the empty\n\t// string and would therefore rewrite the entire body).\n\tErrInvalidRule = errors.New(\"redact: invalid redaction rule\")\n\t// ErrRuleUnsupported means the rule's type is not implementable against an\n\t// opaque body by this pass.\n\tErrRuleUnsupported = errors.New(\"redact: unsupported redaction rule type\")\n)\n\n// Rule is one enabled row of the redaction_rules table, minus the columns that\n// are the caller's business. Field names and JSON tags are pinned to that\n// table's columns so the two cannot drift.\n//\n// Deliberately absent:\n//   - id / organization_id / project_id — tenancy is the caller's concern.\n//   - enabled — filtering disabled rows is the caller's concern; a rule that\n//     reaches Payload is a rule that runs.\n//\n// A row with rule_type='builtin' is accepted and treated as a no-op reference:\n// the built-in floor is unconditional, so such a row can neither add to nor\n// subtract from it.\ntype Rule struct {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/redact/payload.go#L54-L90","documentation":"ErrInvalidRule is returned by compileOrgRules when a redaction Rule row cannot be turned into a working matcher: the rule Name is empty/whitespace, the Pattern is empty, the regex fails to compile, or the pattern matches the empty string (which would rewrite the entire body). Payload surfaces it before any redaction is attempted, so one bad org rule blocks the whole pass.","triggerScenarios":"Inserting a redaction_rules row with an empty name or pattern; a rule pattern that is not a valid Go regexp (e.g. \"(\"); a pattern like \"a*\" that matches the empty string; passing org rules from a DB migration that defaulted columns to ''.","commonSituations":"An admin saving a rule via a UI that allows blank pattern fields; regexes copied from other engines (PCRE/RE2 syntax differences) failing Go's regexp.Compile; seeding scripts inserting placeholder rows with empty values.","solutions":["Fix the offending rule row: give it a non-empty name and a compiling, non-empty matching pattern","Test the pattern with regexp.Compile before persisting it to redaction_rules","Validate rules at rule-management time (admin API/UI) so bad rows never reach the redaction pass","Read the wrapped %w detail in the error — it names the rule and the exact structural problem"],"exampleFix":"// before\nredact.Rule{Name: \"\", Pattern: \"a*\"} // invalid: empty name, empty-matching pattern\n// after\nredact.Rule{Name: \"api-key\", Pattern: \"(?i)sk-[a-z0-9]{16,}\"}","handlingStrategy":"validation","validationCode":"func validRule(r redact.Rule) error {\n    if strings.TrimSpace(r.Name) == \"\" { return fmt.Errorf(\"rule name required\") }\n    if r.Pattern == \"\" { return fmt.Errorf(\"rule %q pattern required\", r.Name) }\n    if _, err := regexp.Compile(r.Pattern); err != nil { return fmt.Errorf(\"rule %q: %w\", r.Name, err) }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"redacted, report, err := redact.Payload(body, rules)\nif err != nil && errors.Is(err, redact.ErrInvalidRule) {\n    log.Errorf(\"bad redaction rule, skipping pass: %v\", err) // err names the rule\n    return err\n}","preventionTips":["Validate name/pattern/regex at rule-creation time (admin UI and API), not just at redaction time","Avoid empty-matching patterns like a* or .*? that rewrite the whole body","Use Go's regexp (RE2) syntax when authoring patterns for other tools","Add a CHECK constraint or validator on redaction_rules before insert"],"tags":["redaction","regex","validation","configuration"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}