{"record":{"id":"8b25b1716c8727e0","repo":"caddyserver/caddy","slug":"cannot-add-operation-maximum-d-operations-allowe","errorCode":null,"errorMessage":"cannot add operation: maximum %d operations allowed","messagePattern":"cannot add operation: maximum (.+?) operations allowed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/logging/filters.go","lineNumber":1000,"sourceCode":"\tfor _, op := range f.Operations {\n\t\t// Each regexp operation is applied sequentially\n\t\t// Using RE2 engine which is safe from ReDoS attacks\n\t\tresult = op.regexp.ReplaceAllString(result, op.Value)\n\n\t\t// Ensure result doesn't exceed max length after each operation\n\t\tif len(result) > maxInputLength {\n\t\t\tresult = result[:maxInputLength]\n\t\t}\n\t}\n\treturn result\n}\n\n// AddOperation adds a single regexp operation to the filter with validation.\n// This is used when merging multiple RegexpFilter instances.\nfunc (f *MultiRegexpFilter) AddOperation(rawRegexp, value string) error {\n\t// Security checks\n\tif len(f.Operations) >= maxRegexpOperations {\n\t\treturn fmt.Errorf(\"cannot add operation: maximum %d operations allowed\", maxRegexpOperations)\n\t}\n\n\tif rawRegexp == \"\" {\n\t\treturn fmt.Errorf(\"regexp pattern cannot be empty\")\n\t}\n\n\tif len(rawRegexp) > maxPatternLength {\n\t\treturn fmt.Errorf(\"regexp pattern too long: %d characters (maximum %d)\", len(rawRegexp), maxPatternLength)\n\t}\n\n\tf.Operations = append(f.Operations, regexpFilterOperation{\n\t\tRawRegexp: rawRegexp,\n\t\tValue:     value,\n\t})\n\treturn nil\n}\n\n// RenameFilter is a Caddy log field filter that","sourceCodeStart":982,"sourceCodeEnd":1018,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/logging/filters.go#L982-L1018","documentation":"MultiRegexpFilter.AddOperation returns this when the filter already holds maxRegexpOperations (50) entries and another is added. AddOperation is used when merging multiple RegexpFilter instances into one MultiRegexpFilter, so this protects the same 50-op ceiling during merge as Validate does at config time.","triggerScenarios":"Calling AddOperation on a MultiRegexpFilter that already has 50 operations, e.g. when Caddy (or plugin code) merges several single RegexpFilter configs into a multi filter and the combined count exceeds 50.","commonSituations":"A config lists many individual 'filter': 'regexp' entries that the logging pipeline coalesces into a MultiRegexpFilter; plugin authors building filters programmatically in a loop without checking the cap.","solutions":["Reduce the number of regexp filters being merged (drop or combine entries)","Check len(f.Operations) < 50 before each AddOperation call in your own code and stop or split gracefully","Restructure to explicit multi_regexp blocks you control, staying under 50"],"exampleFix":"// before\nfor _, op := range ops {\n    _ = mf.AddOperation(op.search, op.replace) // fails silently past 50\n}\n\n// after\nfor _, op := range ops {\n    if err := mf.AddOperation(op.search, op.replace); err != nil {\n        log.Fatal(err) // or split into a new MultiRegexpFilter\n    }\n}","handlingStrategy":"validation","validationCode":"if len(mf.Operations) >= 50 {\n    return fmt.Errorf(\"cannot add operation %d: split the filter\", len(mf.Operations))\n}\nif err := mf.AddOperation(search, replace); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := mf.AddOperation(p, v); err != nil {\n    if strings.Contains(err.Error(), \"maximum\") { /* split into a new filter */ }\n    return err\n}","preventionTips":["Track the running operation count in merge loops","Design merge code to spill into a new MultiRegexpFilter at the cap"],"tags":["caddy","logging","regexp","limits"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}